为什么指针(*)和数组([])符号绑定在变量名而不是变量类型上进行声明?

3

在SO上有很多关于C(和C++子集)中指针和数组声明细节的问题。

然而,我更感兴趣的是为什么

当我们连续声明几个指针/数组时,为什么每个变量前都要放置*[]

int *a, *b;
int c[1], d[1];

为什么在函数指针中变量名后/周围要输入内容?

void (*foo_ptr)(int, int);

为什么即使编译器将这些东西作为类型的一部分进行识别和报告,我们还会有这种让很多新手感到困惑的功能呢?例如:function foo接受int **,但给出了int * 我猜我正在寻找它被创建的原因的直觉,以便我可以将其应用于对语言的理解上。现在我只是看不到它...

@Mat 这是指针符号紧挨名称的结果,而不是原因。我相信在 C++ 的 std::function 中,这个问题已经通过 void*(int, int)void(int, int)* 得到了解决。 - Noone AtAll
@EricPostpischil 我在询问语言设计背后的直觉/逻辑。我知道有一些解决方法,但那不是我想要的。 - Noone AtAll
1
逻辑是声明声明了一系列东西;int X,Y,Z;XYZ 声明为 int,而且每个 XYZ 都是某个表达式的“图片”,例如 b*bb[10]*b[10] 等等。声明的标识符的实际类型源自于这个“图片”: 由于 *b[10] 是一个 int,那么 b[10] 就是指向 int 的指针,所以 b 是一个包含 10 个指向 int 的指针的数组。 - Eric Postpischil
1
@NooneAtAll:那些不容易符合模式的怎么办?在 int X = 0, Y = 0 中,X 是“图像” a,而 Y 是“图像” “*b”。 - Eric Postpischil
@NooneAtAll:只有 X 部分是图片;= initial value 是单独的,它指定了被声明的东西的初始值,而不是所示表达式的初始值。 - Eric Postpischil
显示剩余6条评论
2个回答

9
Kernighan和Ritchie在1978年的The C Programming Language第90页写道:

指针px的声明是新的。

int *px;

这是一种记忆方法;它表示组合*px是一个int,也就是说,如果px出现在上下文*px中,则等同于类型为int的变量。实际上,变量声明的语法模仿了变量可能出现的表达式的语法。这种推理在涉及复杂声明的所有情况下都很有用。例如,

double atof(), *dp;

表示在表达式atof()*dp中,它们的值是double类型。

因此,我们可以看到,在声明中,如int X,Y,ZXYZ给我们“表达式”的图像,例如b*bb[10]*b[10]等。声明标识符的实际类型是根据该图像派生的:由于*b[10]是一个int,因此b[10]是一个指向int的指针,所以b是一个包含10个指向int的指针的数组。

0
为什么我们在声明多个指针/数组时,每个变量前都要加上*、[]呢?
答案是:显式比隐式更好。在这种情况下,我们甚至可以在同一行上声明不同类型的变量,例如int *a, *b, c;等等,否则会非常混乱。对于第二个问题也是如此。

为什么“在同一行上声明不同类型”是一件好事?为什么明确声明类型“int指针”一次比声明“这一行是用于整数,这个变量是一个指针,这个变量是一个指针,这个变量是一个指针”更糟糕? - Noone AtAll
1
指针只是一个包含指定类型对象地址的变量。如果我们有“int指针”,那么我们需要为每种现有类型创建“特殊”的指针符号。 - funnydman
我认为你的评论给了我启示...但是我没有足够的信息,也没有足够的信任来确认它。所以,请解释一下你的理由:为什么“包含类型地址的变量”应该与“类型变量”同等对待?(而且指针符号不是已经成为“每种现有类型的特殊指针符号”了吗?) - Noone AtAll
这里的 int *pt 中,pt 是一个指针(存储某个 int 的地址)。在这种情况下,int 表示指针包含不同 int 的地址。因此,例如,char *c 包含某个不同 char 的地址。因此,写成 int a, *p - 我们声明 a 本身具有类型 int,而 *p 指的是 int。这样做是为了使事情更加一致。我想要处理 intPointerInt 类型等会更加困难... - funnydman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接