C中的指针语法:为什么*仅适用于第一个变量?

时间:2010-07-15 23:11:26

标签: c syntax pointers language-design

C中的以下声明:

int* a, b;

会将a声明为int*类型,将b声明为类型int。我很清楚这个陷阱,但我想知道的是为什么它以这种方式工作。为什么不像大多数人直觉所期望的那样将b声明为int*?换句话说,为什么*适用于变量名称,而不是类型?

当然,你可以这样写,以便与实际的工作原理更加一致:

int *a, b;

但是,我和我所说过的每个人都认为 a是“指向int”的类型,而不是 a是指向某些数据的指针和类型该数据为“int”

这对C的设计师来说简直是一个糟糕的决定,还是有一些很好的理由为什么它会以这种方式解析?我确定之前已经回答了这个问题,但我似乎无法通过搜索找到它。

8 个答案:

答案 0 :(得分:31)

C语句以这种方式编写,以便“声明镜像使用”。这就是你声明这样的数组的原因:

int a[10];

你是否拥有你提出的规则,总是

type identifier, identifier, identifier, ... ;

...那么数组逻辑上必须像这样声明:

int[10] a;

这很好,但不反映使用 a的方式。请注意,这也适用于函数 - 我们声明这样的函数:

void foo(int a, char *b);

而不是

void(int a, char* b) foo;

通常,“声明镜像使用”规则意味着您只需要记住一组关联性规则,这些规则适用于*[]()等运算符。您正在使用该值以及*[]()等声明符中的相应标记。


经过深思熟虑后,我认为值得指出的是,拼写“指向int 的指针”为“int*”只是“声明镜像使用”的结果。如果你打算使用另一种声明方式,将“指向int ”的指针拼写为“&int”,或者像“{{1}”这样完全不同的东西可能会更有意义。 }”。

答案 1 :(得分:17)

The Development of the C Language上有一个网页,上面写着:“这些声明的语法反映了i,* pi和** ppi在表达式中使用时都会产生int类型的观察结果。”在页面上搜索该句子以找到谈论此问题的相关部分。

答案 2 :(得分:9)

可能还有其他历史原因,但我总是这样理解:

一种声明,一种类型。

如果a,b,c和d必须与此类型相同:

int a, b, c, d;

然后行上的所有内容也必须是整数。

int a, *b, **c, ***d;

4个整数:

  1. 一个
  2. * B
  3. **ç
  4. *** d
  5. 它也可能与运算符优先级有关,或者它可能在过去的某个时刻。

答案 3 :(得分:2)

*修改变量名称,而不是类型说明符。这主要是因为*被解析的方式。请听这些陈述:

char*  x;
char  *x;

这些陈述是等同的。 *运算符需要在类型说明符和变量名之间(它被视为中缀运算符),但它可以位于空格的任一侧。鉴于此,宣言

int*  a, b;

不会使b成为指针,因为它旁边没有**仅对其两侧的对象进行操作。

另外,请考虑这种方式:当您编写声明int x;时,表明x是一个整数。如果y是指向整数的指针,则*y是整数。当您编写int *y;时,表示*y是一个整数(这是您想要的)。在语句char a, *b, ***c;中,您指出变量ab的解除引用值以及c的三重取消引用值都是{{1}类型}}。以这种方式声明变量使得星号运算符的使用(几乎)与解除引用一致。

我同意它反过来更有意义。为了避免这个陷阱,我总是把自己作为一条规则来自己在一条线上声明指针。

答案 4 :(得分:2)

我认为它与类型修饰符的完整声明语法有关:

int x[20], y;
int (*fp)(), z;

在这些示例中,更明显的是修饰符只影响其中一个声明。一种猜测是,一旦K& R决定以这种方式设计修饰符,让修饰符仅影响一个声明感觉“正确”。

另一方面,我建议将每个声明限制为一个变量:

int *x;
int y;

答案 5 :(得分:1)

因为如果声明

int* a, b;

也要将b声明为指针,那么你就没有办法宣布

int* a;
int  b;

在一条线上。

另一方面,你可以做到

int*a, *b;

得到你想要的东西。

这样想:它现在的方式仍然是最简洁而又独特的方式。那就是C主要是关于:)

答案 6 :(得分:1)

考虑声明:

int *a[10];
int (*b)[10];

第一个是十个整数指针的数组,第二个是指向十个整数数组的指针。

现在,如果*附加到类型声明,则在它们之间放置一个括号在语法上是无效的。所以你必须找到另一种方法来区分这两种形式。

答案 7 :(得分:0)

我只能猜测为什么必须为一行上提到的每个变量名重复*以使它们成为所有指针。 也许这是由于对语言一致性的决定?让我用一个例子来说明这一点:


假设你有一个函数foo声明如下:

int foo() { ... }

我们还假设您要声明两个函数指向此函数:

int (*fooptr1, fooptr2)();
// this doesn't work; and even if it did, what would the syntax possibly
// look like to initializing them to function foo?
// int (*fooptr1 = foo, fooptr2 = foo)() ?

int (*fooptr1)() = foo, (*fooptr2)() = foo;
// this works.

在这种情况下,您只需必须重复两个变量的整个类型声明,并且您不会出错,因为没有其他方法可以做到这一点(给定C声明语法,因为它是)。


现在,也许有人认为,如果有必要为所有变量重复类型声明的情况,也许这应该只是一般情况。

(不要忘记我只是在这里猜测。)