6.6 Ссылка на тип с помощью typeof
Другой способ сослаться на тип выражения — с помощью typeof. Синтаксис использования этого ключевого слова выглядит как sizeof, но конструкция по смыслу действует как имя типа, определённое с помощью typedef.
Существует два способа записи аргумента для typeof: с помощью выражения или с помощью типа. Вот пример с выражением:
typeof (x[0](1))
Это предполагает, что x является массивом указателей на функции; описываемый тип — тип значений функций.
Вот пример с именем типа в качестве аргумента:
typeof (int *)
Здесь описываемый тип — тип указателей на int.
Если вы пишете заголовочный файл, который должен работать при включении в программы ISO C, запишите __typeof__ вместо typeof. См. Альтернативные ключевые слова.
Конструкцию typeof можно использовать везде, где можно использовать имя typedef. Например, вы можете использовать его в объявлении, в приведении типа или внутри sizeof или typeof.
Операнд typeof вычисляется для побочных эффектов только в том случае, если это выражение с изменяемым типом или имя такого типа.
typeof часто полезно в сочетании с выражениями-высказываниями (см. Выражения-высказывания). Вот как эти два вместе можно использовать для определения безопасной макрокоманды «максимум», которая работает с любым арифметическим типом и вычисляет каждый из её аргументов ровно один раз:
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; }) Причина использования имён, начинающихся с нижнего подчёркивания для локальных переменных — избежать конфликтов с именами переменных, которые встречаются внутри выражений, заменяющих a и b. В конечном итоге мы надеемся разработать новый синтаксис объявления, который позволит объявлять переменные, область действия которых начинается только после их инициализаторов; это будет более надёжным способом предотвращения таких конфликтов.
Ещё несколько примеров использования typeof:
- Это объявляет
yс типом того, на что указываетx.typeof (*x) y;
- Это объявляет
yкак массив таких значений.typeof (*x) y[4];
- Это объявляет
yкак массив указателей на символы:typeof (typeof (char *)[4]) y;
Это эквивалентно следующему традиционному объявлению на C:
char *y[4];
Чтобы увидеть значение объявления с помощью
typeof, и почему это может быть полезным способом написания, перепишите его с помощью этих макросов:#define pointer(T) typeof(T *) #define array(T, N) typeof(T [N])
Теперь объявление можно переписать так:
array (pointer (char), 4) y;
Таким образом,
array (pointer (char), 4)— это тип массивов из 4 указателей наchar.
В GNU C, но не в GNU C++, вы также можете объявить тип переменной как __auto_type. В этом случае объявление должно объявлять только одну переменную, декларатор которой должен быть только идентификатором, объявление должно быть инициализировано, а тип переменной определяется инициализатором; имя переменной не находится в области видимости до инициализатора. (В C++ для этой цели следует использовать C++11 auto.) Используя __auto_type, макрос «максимум» выше можно переписать как:
#define max(a,b) \
({ __auto_type _a = (a); \
__auto_type _b = (b); \
_a > _b ? _a : _b; }) Использование __auto_type вместо typeof имеет два преимущества:
- Каждый аргумент макроса появляется только один раз в развёртывании макроса. Это предотвращает экспоненциальный рост размера развёртывания макроса, когда вызовы таких макросов вложены в аргументы таких макросов.
- Если аргумент макроса имеет изменяемый тип, он вычисляется только один раз при использовании
__auto_type, но дважды, если используетсяtypeof.
Примечание о совместимости: В дополнение к typeof, GCC 2 поддерживал более ограниченное расширение, которое позволяло написать
typedef T = expr;
с эффектом объявления T с типом выражения expr. Это расширение не работает с GCC 3 (версии между 3.0 и 3.2 аварийно завершаются; 3.2.1 и более поздние версии возвращают ошибку). Код, зависящий от него, следует переписать, используя typeof:
typedef typeof(expr) T;
Это работает со всеми версиями GCC.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Typeof.html