Автостопом по GNU C

Будучи разработчиком встраиваемых систем в течение многих лет, я провел больше времени с GCC, чем с любым другим инструментом, и получение от него максимальной отдачи было приятным путешествием.

Ниже приведены мои любимые трюки и советы GCC в произвольном порядке, которые со временем будут обновляться и предлагаться.

Если для вас важна переносимость, вам, вероятно, следует поискать в другом месте. Но если вы разработчик Linux, творческий производитель Arduino или разработчик встраиваемых систем, есть шанс, что GCC будет единственным целевым компилятором. Так почему бы не выбрать удобную дорогу? В конце концов, исходный код ядра Linux непереносим, ​​и никого это не волнует.

Функция очистки переменных

cleanup атрибут переменной запускает функцию, когда переменная выходит за пределы области видимости. Для удобства функции будет передан указатель на переменную:

Одно из моих любимых применений атрибута cleanup - автоматическое снятие блокировки в методе, обращающемся к взаимоисключающему ресурсу:

Слабая функция

Атрибут функции weak приводит к тому, что объявление генерируется как слабый символ вместо глобального, что делает его переопределяемым:

В качестве приятного побочного эффекта неопределенные слабые функции оцениваются как null и могут пригодиться, например, для реализации некоторых дополнительных определяемых пользователем хуков в вашей библиотеке:

Наконец, атрибут функции weak очень хорошо сочетается с alias для объявления реализации по умолчанию:

Автоматический вывод типа

В GNU C появилось ключевое слово __auto_type. Возможно, вы уже знаете, что typeof относится к типу выражения:

Конструкцию typeof можно использовать везде, где можно использовать typedef имя: вы можете использовать ее в объявлении, в приведении или внутри sizeof или typeof.

В GNU C, подобно ключевому слову C ++ 11 auto, вы также можете объявить тип переменной как __auto_type:

Приведенный выше макрос работает с любым арифметическим типом и оценивает каждый из его аргументов только один раз.

Преимущество __auto_type в приведенном выше макросе состоит в том, что каждый аргумент макроса появляется только при раскрытии, предотвращая экспоненциальный рост размера расширения макроса, когда вызовы таких макросов вложены в аргументы таких макросов. Более того, если аргумент типа макроса имеет изменяемый тип, он оценивается только один раз при использовании __auto_type и дважды, если используется typeof.

Функция оболочки

Параметр компоновщика GNU --wrap=symbol предоставляет функцию-оболочку для данного символа. Функция-оболочка должна вызываться __wrap_symbol, а функция-оболочка может быть вызвана через __real_symbol:

Диапазоны случаев

GCC позволяет указывать диапазон последовательных значений в одной метке case:

Назначенные инициализаторы

ISO C99 упростил инициализацию элементов, разрешив указывать индексы массива или имена полей структуры во время инициализации. GNU C допускает это расширение в режиме C90 также вместе с инициализацией диапазона массивов:

Влить в Союз

Приведение к типу объединения аналогично другим приведениям, за исключением того, что указанный тип является типом объединения:

Приведение к объединению на самом деле является конструктором, а не приведением, и, следовательно, не дает lvalue, как обычные приведения (см. Составные литералы).

Неназванные поля структуры

Введенные в ISO C11, безымянные поля структуры и объединения задолго до этого поддерживались GCC:

Одним из наиболее простых способов использования такой функции является декомпозиция, которая также очень хорошо сочетается с полями приведение к объединению и битовыми полями. Обратите внимание, что приведенные ниже примеры поддерживают порядок байтов с прямым порядком байтов только для краткости:

Конструктор Функция

Атрибут функции constructor вызывает автоматический вызов функции до того, как выполнение войдет в main(). Точно так же атрибут destructor вызывает автоматический вызов функции после завершения main() или вызова exit():

Вы можете указать необязательный целочисленный приоритет для управления порядком, в котором выполняются функции constructor и destructor. Конструктор с меньшим номером приоритета запускается перед конструктором с большим номером приоритета; обратное соотношение верно для деструкторов:

Составные литералы

Составной литерал обозначает безымянный объект: его значение является объектом типа, указанного в приведении, это lvalue. Поддерживаемый в ISO C99, GCC также поддерживает составные литералы в режиме C90:

Вложенные функции

вложенная функция - это функция, определенная внутри другой функции. Благодаря лексической области видимости вложенная функция может получить доступ ко всем переменным содержащейся функции, которые видны в точке определения:

Массивы нулевой длины

Массивы нулевой длины разрешены в GNU C и действительно полезны в качестве последнего элемента структуры, которая является заголовком для объекта переменной длины:

Помните, что непустая инициализация массивов нулевой длины обрабатывается как лишние элементы и игнорируется: в качестве альтернативы (и для удобства) GCC позволяет статическую инициализацию гибкого члена массива:

Массивы переменной длины

Массивы переменной длины разрешены в ISO C99, и GCC принимает их в режиме C90 как расширение:

Поддержка смещения (и не только)

Макрос offsetof оценивает смещение (в байтах) данного члена в структуре или типе объединения. Макрос offsetof принимает два параметра, первый из которых является именем структуры, а второй - именем члена в структуре:

Реальным примером макроса offsetof может быть макрос Linux Kernel container_of:

Прозрачный союз

Атрибут переменной transparent_union, когда он прикреплен к определению типа union, указывает, что любой параметр функции, имеющий этот тип объединения, вызывает особую обработку вызовов этой функции: аргумент, соответствующий прозрачному типу объединения, может быть любого типа в союз; Приведение не требуется:

Натягивание

Когда параметр макроса используется с начальным #, препроцессор заменяет его буквальным текстом фактического аргумента, преобразованным в строковую константу:

Помните, что преобразование результата раскрытия аргумента макроса в строку требует двух уровней макросов:

Конкатенация

Может быть полезно объединение двух токенов в один при расширении макросов. Оператор предварительной обработки ## выполняет конкатенацию токенов:

Я бы рекомендовал использовать несколько помощников для повторного использования:

Повторить макрос

Благодаря оператору предварительной обработки конкатенация можно написать REPEAT вспомогательный макрос для получения повторяющихся конструкций:

Шаблонизатор для бедняков

Оператор предварительной обработки конкатенация вместе с #include позволяет создавать базовые шаблоны:

Утверждения времени компиляции

В C11 введено _Static_assert ключевое слово для утверждений во время компиляции, но если вы используете GCC 4.5 или ниже, существует обходной путь:

На этом пока все! Вышеупомянутая статья написана с, не стесняйтесь делиться и не забывайте хлопать, если вам это понравилось!