| Есть еще один способ указать тип выражения - 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 лента комментариев этой записи