Когда вы объявляете указатель на int:

int *a, b;

a - это указатель на int, тогда как b - это int (я никогда не понимал, почему это происходит, я знаю, что это связано с запятой, но я раньше говорил что звездочка привязана к имени переменной, а не к типу данных). Во всяком случае, если вы:

#define intptr int*
intptr a, b

Результат тот же. Мне кажется странным, почему использование typedef для одного и того же меняет поведение?

typdef int* intptr 
intptr a, b;

В последнем примере я ожидал, что a будет int*, тогда как b будет int. Вместо этого они оба int*


Для пояснения, имея следующий фрагмент кода, я не понимаю, почему я не получаю такое же предупреждение для переменной d

#define intptr_def int*

typedef int* intptr_typ;

int main()
{
    int x;

    intptr_def a, b;
    intptr_typ c, d;

    a = &x;
    b = &x;     // Warning assignment to 'int' from 'int *' makes integer from pointer without a cast
    c = &x;
    d = &x;

    return 0;
}
0
Cătălina Sîrbu 30 Ноя 2020 в 00:21

1 ответ

Лучший ответ

Макрос - это подстановка текста, не более того. Если у вас есть

#define intptr int*

И написать

intptr a, b;

Затем при предварительной обработке кода макрос intptr расширяется до

int* a, b;

Который обрабатывается точно так же, как

int *a, b;

И объявляет только a как указатель; b - это обычный int.

Имя typedef - это псевдоним для типа, а не текстовая подстановка, как макрос препроцессора.

typedef int *intptr;

Создает intptr как псевдоним для int * (указатель на int). Итак, когда вы пишете

intptr a, b;

И a, и b имеют тип intptr (int *).


Объявления в C имеют базовую структуру

declaration-specifiers declarators

Спецификаторы декларации включают спецификаторы типа (int, float, char и т. Д.), Квалификаторы типа (const, volatile), спецификаторы класса хранения (static, auto, register) и несколько других спецификаторов, связанных с объявлениями / определениями функций.

declarator вводит имя объявляемого объекта, а также информацию о его массивности, свойствах указателя и функции. Например, в декларации

static volatile unsigned int a[10], *p;

Спецификаторы объявления - static volatile unsigned int, а деклараторы - a[10] и *p. Тип каждой переменной полностью определяется комбинацией спецификаторов объявления и декларатора. Типом a является "10-элементный массив static volatile unsigned int", а типом p является "указатель на static volatile unsigned int".

Идея состоит в том, что структура декларатора соответствует структуре выражения в коде. Например, предположим, что у вас есть указатель на int с именем iptr, и вы хотите распечатать значение в объекте, на который он указывает, вы должны написать

printf( "%d\n", *iptr );

Тип выражения *iptr - int, поэтому объявление записывается как

int *iptr;

Вы также можете написать это как

int* iptr;

Или

int*iptr;

Или даже

int      *      iptr;

И все будет интерпретировано как

int (*iptr);

Пробелы не имеют значения - * всегда является частью декларатора, а не спецификатора объявления. Деклараторы могут быть произвольно сложными - для любой последовательности спецификаторов объявления T вы можете иметь

T x;          // x is an object of type T
T a[N];       // a is an array of T
T *p;         // p is a pointer to T
T f();        // f is a function returning T

T *a[N];      // a is an array of pointer to T
T (*p)[N];    // p is a pointer to an array of T
T *f();       // f is a function returning pointer to T
T (*p)();     // p is a pointer to a function returning T

T *(*a[N])(); // a is an array of pointers to functions
              // returning pointer to T

И это почти не касается поверхности.

3
John Bode 29 Ноя 2020 в 22:22