Пожалуйста, объясните правила синтаксиса и область действия для "typedef"
Каковы правила? OTOH простой случай, по-видимому, подразумевает, что новый тип является последним на линии. Например, здесь Uchar
- новый тип:
typedef unsigned char Uchar;
Но указатель на функцию полностью отличается. Здесь новый тип pFunc
:
typedef int (*pFunc)(int);
Я не могу думать о каких-либо других примерах, но я столкнулся с некоторыми очень запутанными обычаями.
Итак, есть ли правила или люди просто должны знать из опыта, что так оно и делается, потому что они видели это раньше?
ТАКЖЕ: Какова область действия typedef
?
Ответы
Ответ 1
В принципе, typedef
имеет тот же синтаксис, что и объявление объекта, за исключением того, что он имеет префикс с typedef
, и это изменяет значение, чтобы новый идентификатор объявлял псевдоним для того типа, который был объявлен объектом если бы это была нормальная декларация.
A typedef
определяется как объявление объекта, поэтому оно может быть скопировано или локально в блок или (на С++) в пространство имен или класс.
например.
Объявляет int
:
int a;
Объявляет тип, который является псевдонимом для int
:
typedef int a_type;
Объявляет указатель на char
:
char *p;
Объявляет псевдоним для char *
:
typedef char *pChar;
Объявляет указатель на функцию:
int (*pFn)(int);
Объявляет псевдоним для типа, который является "указателем на функцию, принимающую int
и возвращающей int
":
typedef int (*pFunc)(int);
Ответ 2
Для удобства синтаксиса typedef
рассматривается как спецификатор класса хранения, например extern
, static
или register
. Семантически, конечно, это совсем другое, но когда typedef
был добавлен в язык, было проще использовать существующий фрагмент грамматики для определения его синтаксиса.
Добавление static
к объявлению объекта не изменяет значения декларации, за исключением того, что он изменяет класс хранения объекта на "статический" (если он еще не был):
{
int foo; /* automatic storage duration */
static int bar; /* static storage duration */
}
Замена static
на typedef
изменяет значение объявления, так что определяемое имя не является именем объекта, а именем типа (фактически просто псевдонимом для существующего типа):
typedef int baz; /* "baz" is an alias for "int" */
Тот же синтаксис применяется к более сложным объявлениям:
int (*a)[42]; /* a is a pointer to an array of 42 ints */
static int (*b)[42]; /* Same as a, but with static storage duration */
typedef int (*c)[42] /* c is an alias for the type int(*)[42], or
"pointer to array of 42 ints" */
Как только вы поймете, что typedef
был произвольно сунут в тот же слот в грамматике, занятой extern
, static
и register
, понимание объявлений typedef
не сложнее (и не проще!), чем понимание деклараций объектов. (Программа cdecl
и веб-сайт полезны для распаковки сложных объявлений.)
Вы также можете иметь typedef
для типа функции:
void func(void); /* declare func as a function */
typedef void func_type(void); /* declare func_type as a name
for a function type */
Вы не можете использовать тип функции typedef
ed для объявления или определения функции, но вы можете использовать ее для объявления указателя функции:
func_type *ptr = func;
Что касается области (то есть области текста программы, над которой отображается объявленный идентификатор), идентификатор, определенный объявлением typedef
, имеет ту же область действия, что и любой другой объявленный идентификатор. Если он объявлен в области файла, вне любой функции, он отображается с точки объявления до конца файла. Если он объявлен внутри функции, он отображается с того места, где он был объявлен в конец ближайшего закрывающего блока. И как любое объявление, он может быть скрыт другим объявлением с тем же именем во внутренней области.