В C, какой правильный синтаксис для объявления указателей?
Я смутно вспоминаю об этом раньше, отвечая на другой вопрос, но поиск не дал ответа.
Я не могу вспомнить, как правильно объявлять переменные, являющиеся указателями. Это:
Type* instance;
Или:
Type *instance;
Хотя я знаю, что оба будут компилироваться в большинстве случаев, я считаю, что есть некоторые примеры, где это важно, возможно, связано с объявлением нескольких переменных одного и того же типа в одной строке, и поэтому имеет смысл, чем другой.
Ответы
Ответ 1
Это просто вопрос того, как вам нравится читать его.
Причина, по которой некоторые люди выразились так:
Type *instance;
Это потому, что он говорит, что только экземпляр является указателем. Потому что, если у вас есть список переменных:
int* a, b, c;
Только a - это указатель, поэтому так проще
int *a, b, c, *d;
Где и a, и d - указатели. Это на самом деле не имеет значения, это просто читаемость.
Другим людям нравится иметь * рядом с типом, потому что (среди других причин) они считают его "указателем на целое число" и считают, что * принадлежит типу, а не переменной.
Лично я всегда делаю
Type *instance;
Но это действительно зависит от вас и руководства по стилю вашей компании/школьного кода.
Ответ 2
Эти два одинаковые. Однако, если вы выполняете несколько заявлений, первые могут вас поймать.
int* pi, j;
объявляет указатель int (pi
) и int (j
).
Ответ 3
Это случайность синтаксиса C, которую вы можете записать в любом случае; однако он всегда анализируется как
Type (*pointer);
то есть *
всегда привязан к объявлению, а не спецификатору типа. Если вы написали
Type* pointer1, pointer2;
он будет анализироваться как
Type (*pointer1), pointer2;
поэтому только указатель1 будет объявлен как тип указателя.
C следует "парадигма использования имиджа"; структура декларации должна как можно больше имитировать эквивалентное выражение, используемое в коде. Например, если у вас есть массив указателей на int с именем arr
, и вы хотите получить целочисленное значение, на которое указывает i-й элемент в массиве, вы должны индексировать массив и разыгрывать результат, который написан как *arr[i]
(анализируется как *(arr[i])
). Тип выражения *arr[i]
равен int
, поэтому декларация для arr
записывается как
int *arr[N];
Какой путь прав? Зависит от того, кого вы спрашиваете. Старый C farts, как и я, предпочитает T *p
, потому что он отражает то, что на самом деле происходит в грамматике. Многие программисты на C++ предпочитают T* p
, потому что он подчеркивает тип p
, который во многих случаях кажется более естественным (написав мои собственные типы контейнеров, я могу видеть это, хотя он по-прежнему мне не нравится).
Если вы хотите объявить несколько указателей, вы можете объявить их явно, например:
T *p1, *p2, *p3;
или вы можете создать typedef:
typedef T *tptr;
tptr p1, p2, p3;
хотя лично я не рекомендую; скрытие указателя-чего-то за typedef может укусить вас, если вы не будете осторожны.
Ответ 4
Эти два точно такие же.
Однако для целей объявления нескольких переменных, как показано ниже:
int * p1, p2;
где p1 имеет указатель на тип int, но p2 имеет тип int. Если вы хотите объявить p2 как указатель на int, вам нужно написать:
int *p1, *p2;
Ответ 5
Я предпочитаю следующий стиль:
Type *pointer;
Почему? Потому что это согласуется с мышлением, созданным создателями языка:
"Синтаксис объявления для переменной имитирует синтаксис выражений, в которых может отображаться переменная.
( Язык программирования C от Brian W. Kernighan и Dennis M. Ritchie, версия ansi c, страница 94)
Легко писать FORTRAN на любом языке, но вы всегда должны писать [язык программирования X] в [языке программирования X].
Ответ 6
Любопытно, что это правило не применяется, если тип выводится в С++ 0x.
int a;
decltype(&a) i, j;
Оба я и j являются int *.
Ответ 7
Все они будут компилироваться, являются законными и эквивалентны:
Type* instance;
Type * instance;
Type *instance;
Выберите стиль и будьте последовательны.
Ответ 8
Как побочная заметка, я думаю, что это помогает понять мотивацию синтаксиса объявления C, которая предназначена для имитации использования переменной. Ниже приведены некоторые примеры:
-
char *x
означает, что если вы выполните *x
, вы получите char
.
-
int f(int x)
означает, что если вы это сделаете, например, f(0)
, вы получите int
.
-
const char *foo[3]
означает, что если вы это сделаете, например, *foo[0]
(что совпадает с *(foo[0])
), вы получите const char
. Это означает, что foo
должен быть массивом (размером 3 в этом случае) указателей на const char
.
-
unsigned int (*foo)[3]
означает, что если вы это сделаете, например, (*foo)[0]
, вы получите unsigned int
. Это означает, что foo
должен быть указателем на массив unsigned int
(размер 3 в этом случае).
Таким образом, общий синтаксис, следовательно, [what you get] [how you get it]
. Фокус в том, что это можно расширить до [what you get] [how you get it], [how you get it], ...
, чтобы сразу объявить несколько вещей. Следовательно, следующие три объявления -
int *p;
int f(int x);
int a[3];
- можно объединить в одну строку следующим образом (и да, это даже работает для объявлений функций. Они не являются особыми в этом отношении):
int *p, f(int x), a[3];