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

发布于 2024-09-10 02:38:07 字数 501 浏览 8 评论 0原文

C 中的以下声明

int* a, b;

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

当然,您可以这样写,以便与它的实际工作方式更加一致:

int *a, b;

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

这仅仅是 C 设计者的一个错误决定还是有一些很好的理由来解释它?我确信这个问题之前已经得到解答,但我似乎无法使用搜索找到它。

The following declaration in C:

int* a, b;

will declare a as type int* and b as type int. I'm well aware of this trap, but what I want to know is why it works this way. Why doesn't it also declare b as int*, as most people would intuitively expect? In other words, why does * apply to the variable name, rather than the type?

Sure you could write it this way to be more consistent with how it actually works:

int *a, b;

However, I and everyone I've spoken to think in terms of a is of type "pointer to int", rather than a is a pointer to some data and the type of that data is "int".

Was this simply a bad decision by the designers of C or is there some good reason why it's parsed this way? I'm sure the question has been answered before, but I can't seem to find it using the search.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

雨落星ぅ辰 2024-09-17 02:38:07

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”或完全不同的内容可能更有意义“@int”。

C declarations were written this way so that "declaration mirrors use". This is why you declare arrays like this:

int a[10];

Were you to instead have the rule you propose, where it is always

type identifier, identifier, identifier, ... ;

...then arrays would logically have to be declared like this:

int[10] a;

which is fine, but doesn't mirror how you use a. Note that this holds for functions, too - we declare functions like this:

void foo(int a, char *b);

rather than

void(int a, char* b) foo;

In general, the "declaration mirrors use" rule means that you only have to remember one set of associativity rules, which apply to both operators like *, [] and () when you're using the value, and the corresponding tokens in declarators like *, [] and ().


After some further thought, I think it's also worth pointing out that spelling "pointer to int" as "int*" is only a consequence of "declaration mirrors use" anyway. If you were going to use another style of declaration, it would probably make more sense to spell "pointer to int" as "&int", or something completely different like "@int".

冰之心 2024-09-17 02:38:07

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

There's a web page on The Development of the C Language that says, "The syntax of these declarations reflects the observation that i, *pi, and **ppi all yield an int type when used in an expression." Search for that sentence on the page to find the relevant section that talks about this question.

撩心不撩汉 2024-09-17 02:38:07

可能还有一个额外的历史原因,但我一直是这样理解的:

一种声明,一种类型。

如果这里的 a、b、c 和 d 必须是相同的类型:

int a, b, c, d;

那么该行上的所有内容也必须是整数。

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

4 个整数:

  1. a
  2. *b
  3. **c
  4. ***d

它也可能与运算符优先级有关,或者可能与过去的某个时刻有关。

There may be an additional historical reason, but I've always understood it this way:

One declaration, one type.

If a, b, c, and d must be the same type here:

int a, b, c, d;

Then everything on the line must an integer as well.

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

The 4 integers:

  1. a
  2. *b
  3. **c
  4. ***d

It may be related to operator precedence, as well, or it may have been at some point in the past.

当爱已成负担 2024-09-17 02:38:07

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

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

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

附带说明一下,我建议将每个声明限制为一个变量:

int *x;
int y;

I assume it is related to the full declaration syntax for type modifiers:

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

In these examples, it feels much more obvious that the modifiers are only affecting one of the declarations. One guess is that once K&R decided to design modifiers this way, it felt "correct" to have modifiers only affect one declaration.

On a side note, I would recommend just limiting yourself to one variable per declaration:

int *x;
int y;
弄潮 2024-09-17 02:38:07

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

char*  x;
char  *x;

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

int*  a, b;

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

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

我同意相反的情况几乎更有意义。为了避免这个陷阱,我给自己制定了一条规则,始终在一行上声明指针本身。

The * modifies the variable name, not the type specifier. This is mostly because of the way the * is parsed. Take these statements:

char*  x;
char  *x;

Those statements are equivalent. The * operator needs to be between the type specifier and the variable name (it is treated like an infix operator), but it can go on either side of the space. Given this, the declaration

int*  a, b;

would not make b a pointer, because there is no * adjacent to it. The * only operates on the objects on either side of it.

Also, think about it this way: when you write the declaration int x;, you are indicating that x is an integer. If y is a pointer to an integer, then *y is an integer. When you write int *y;, you are indicating that *y is an integer (which is what you want). In the statement char a, *b, ***c;, you are indicating that the variable a, the dereferenced value of b, and the triply-dereferenced value of c are all of type char. Declaring variables in this way makes the usage of the star operator (nearly) consistent with dereferencing.

I agree that it would almost make more sense for it to be the other way around. To avoid this trap, I made myself a rule always to declare pointers on a line by themselves.

卷耳 2024-09-17 02:38:07

考虑这样的声明:

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

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

现在,如果 * 附加到类型声明中,那么在它们之间放置括号在语法上是无效的。因此,您必须找到另一种方法来区分这两种形式。

Consider the declaration:

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

The first is an array of ten pointers to integers, the second is a pointer to an array of ten integers.

Now, if the * was attached to the type declaration, it wouldn't be syntatically valid to put a parenthesis between them. So you'd have to find another way to differentiate between the two forms.

余罪 2024-09-17 02:38:07

因为如果该语句

int* a, b;

也将 b 声明为指针,那么您将无法

int* a;
int  b;

在一行上声明。

另一方面,你可以

int*a, *b;

做得到你想要的。

想想看:现在的方式仍然是最简洁但又独特的方式。这就是 C 的主要内容:)

Because if the statement

int* a, b;

were to declare b as a pointer too, then you would have no way to declare

int* a;
int  b;

on a single line.

On the other hand, you can do

int*a, *b;

to get what you want.

Think about it like that: the way it is now it is still the most concise and yet unique way to do it. That's what C is mostly about :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文