Автостопом по 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 или ниже, существует обходной путь:
На этом пока все! Вышеупомянутая статья написана с, не стесняйтесь делиться и не забывайте хлопать, если вам это понравилось!