Есть еще один способ указать тип выражения - typeof. Его синтаксис похож на sizeof, однако семантически конструкция действует как имя типа, определенное с помощью typedef.
Существует 2 способа указать аргумент для typeof: с помощью выражения или с помощью имени типа. Вот пример с выражением:
Здесь подразумевается, что x это массив указателей на функции; описываемый тип относится к типу возвращаемых значений функций.
Пример с использованием в качестве аргумента имени типа:
Здесь описывается тип указателей на int.
Если вы пишете заголовочный файл, который должен работать при подключении к программам ISO C, то вместо typeof пишите __typeof__ (см. описание альтернативных ключевых слов [2]).
Конструкт typeof может использоваться везде, где можно использовать typedef name. Например, typeof можно использовать в декларации, в приведении типа (cast), или внутри sizeof или typeof.
Операнд typeof оценивается на наличие побочных эффектов тогда и только тогда, когда он является выражением изменяемого типа или именем такого типа.
Использование typeof часто полезно вместе с операторными выражениями (statement expressions, см. [3]). Ниже показан пример, как безопасно определить макрос "максимума", который работает с любыми арифметическими типами, и оценивает каждый из своих аргументов ровно 1 раз:
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
Причина появления здесь нижних подчеркиваний в именах локальных переменных - чтобы избежать конфликтов с именами переменных, которые появляются вы выражениях, которыми подменяются аргументы a и b. Когда-нибудь будет изобретена новая форма синтаксиса декларации, которая позволит вам объявлять переменные, область видимости которых начнется только после их инициализаторов; это будет более надежным способом предотвращения подобных конфликтов.
Вот еще примеры использования typeof:
• Объявление y с типом того, на что указывает x:
• Объявляет y как массив таких значений:
• Декларирует y как массив указателей на символы:
typeof (typeof (char *)[4]) y;
Это эквивалентно традиционному объявлению C:
Чтобы лучше уяснить смысл объявления с помощью 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) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
Использование __auto_type вместо typeof дает 2 преимущества:
- Каждый аргумент макроса появляется только 1 раз при расширении макроса. Это не дает экспоненциально разрастаться размеру кода расширяемого макроса, когда вызовы этих макросов вложены а аргументы таких макросов. - Если аргумент макроса имеет изменяемый тип, то при использовании __auto_type он вычисляется только один раз, но дважды при использовании typeof.
[Ссылки]
1. Referring to a Type with typeof site:gcc.gnu.org. 2. gcc: альтернативные ключевые слова. 3. gcc: операторы и объявления в выражениях. |
Комментарии
#define max(a,b)
({ __auto_type _a = (a);
__auto_type _b = (b);
_a > _b ? _a : _b; })
RSS лента комментариев этой записи