6.12.5 Обращение к типу с помощью 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.
Оператор ISO C23 typeof_unqual доступен в режиме ISO C23, и его результатом является неатомарная версия без квалификаторов того, что возвращает оператор typeof. Альтернативное написание __typeof_unqual__ доступно во всех режимах C и возвращает неатомарную версию без квалификаторов того, что возвращает оператор __typeof__. См. раздел Альтернативные ключевые слова.
В GNU C, но не в GNU C++, также можно объявить тип переменной как __auto_type. В этом случае объявление должно объявлять только одну переменную, ее декларатор должен быть простым идентификатором, объявление должно содержать инициализатор, а тип переменной определяется инициализатором; имя переменной не входит в область видимости до завершения инициализатора. (В C++ для этой цели следует использовать auto из C++11.) С помощью __auto_type приведенный выше макрос «максимум» можно записать так:
#define max(a,b) \
({ __auto_type _a = (a); \
__auto_type _b = (b); \
_a > _b ? _a : _b; })
Использование __auto_type вместо typeof дает два преимущества:
- Каждый аргумент макроса встречается в его развертывании только один раз. Это предотвращает экспоненциальный рост размера развертывания макроса, когда вызовы таких макросов вложены в аргументы других таких макросов.
- Если аргумент макроса имеет тип с переменной модификацией, при использовании
__auto_typeон вычисляется только один раз, а при использованииtypeof— дважды.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/Typeof.html