C++ 为什么必须阅读C中的指针声明背景词?

C++ 为什么必须阅读C中的指针声明背景词?,c++,c,pointers,syntax,C++,C,Pointers,Syntax,在C语言中,对于简单的情况,为了读取指针声明,似乎必须向后进行。例如: int n; int *p = &n; // p is a pointer to int int *const np = &n; // np is a const pointer to int int *const *npp = &np; //npp is a (non-const) pointer to const pointer to (non-const) int int n; *int p

在C语言中,对于简单的情况,为了读取指针声明,似乎必须向后进行。例如:

int n; 
int *p = &n; // p is a pointer to int
int *const np = &n; // np is a const pointer to int
int *const *npp = &np; //npp is a (non-const) pointer to const pointer to (non-const) int
int n;
*int p = &n; // p is a pointer to int
const *int np = &n; // np is a const pointer to int
*const *int npp = &np; // npp is a (non-const) pointer to const pointer to (non-const) int
即使正确的解析类型声明的方法是通过所谓的方法,如果解析规则不同,以便以另一种方式容纳简单指针声明的读取,不是更容易吗? 例如:

int n; 
int *p = &n; // p is a pointer to int
int *const np = &n; // np is a const pointer to int
int *const *npp = &np; //npp is a (non-const) pointer to const pointer to (non-const) int
int n;
*int p = &n; // p is a pointer to int
const *int np = &n; // np is a const pointer to int
*const *int npp = &np; // npp is a (non-const) pointer to const pointer to (non-const) int

那么我的问题是:这种设计选择背后的原则是什么?是什么促使语言设计者选择这种特殊的方式来声明类型。

语法除外。如果我没有弄错背后的想法:

int**a;
下面是一个例子。你需要两次解引用a才能得到一个整数。这样常量位置也就开始有意义了

int*const*a;
这实际上意味着您需要取消引用一次,以获得指向int的常量指针


你可能会发现阅读有关C语言起源的文章既有趣又有教育意义。(PDP、B等)

为什么必须在C中反向读取指针声明

在我看来,很难说这个宣言是否真的倒退了

例如 我注意到,在过去几年中,我在脑海中阅读代码的方式发生了变化

考虑以下代码:

int *p;
你是如何在头脑中理解这些代码的

  • 我曾经读过:“p是指向int的指针”

  • 现在我读到:“一个名为p的int指针”

由于频繁使用这种语言,我的大脑改变了我将源代码翻译成英语的方式。这使我能够理解语法,而不会感觉它是向后的

对我来说,这感觉是向前的,尽管这完全是主观的,而且会因人而异

此外,可能有许多(口语)语言,在这些语言中,源代码可以很好地翻译成口语句子,而无需更改顺序

结论 声明是否有倒退的感觉取决于

  • 你的母语
  • 如何将代码翻译成您的母语
  • 声明的大小/复杂性

我认为这里唯一的非固执己见的答案是“因为历史上对它的定义是这样的”。非固执己见的答案是,一般情况下,你不会向后阅读,只会在简单的情况下阅读。规范的解决方案是.C声明语法实际上相当复杂-对象或函数的类型完全由声明说明符(类型说明符、类型限定符、存储类说明符)和声明符(标识符,加上
*
()
[]的组合指定
操作员)。指针ness、数组ness和函数ness在声明符中指定,与类型说明符分开。这允许您只需几次击键即可创建一些相当复杂的类型;不利的一面是,这些声明很快就变得刺眼。如果Ritchie使用间接运算符后缀而不是一元-
ta[N]*[M]*
更容易理解,因为“a是指向
T
的指针数组的指针数组”,而不是
T*(*a[M])[N]我们在阅读声明时不必来回跳转。但是,他没有。@elFreak:啊。在这种情况下,这是因为B就是这样做的(这是因为BCPL就是这样做的,尽管使用不同的运算符)。C的许多古怪之处可以追溯到B和BCPL。您可能会感兴趣。解引用语法也可以更改。如果我们开始改变事情。。。因此,用另一种语法来证明一种语法的合理性并不是一种真正的方法。@Eugene Sh。这就是我的看法。C是进化而非革命性的,因此它借鉴了前人的一些语法。在我看来,有几个与语法相关的有争议的决定(比如函数声明语法)。此外,C被采用的时间远远早于标准化的时间。然而,在我看来,当时的主要目标是创建一个接近现有实现的标准,否则它将是一种完全不同的语言,不会被采用。后来,这一切都是关于向后兼容性的。那么,我们可以问一下前辈们是否也一样?我们在哪里停?这就是为什么这个问题可能会以基于意见的方式结束。@EugeneSh。虽然您可能不喜欢,但C的创建者确实设计了从表达式到类型声明的语言。遵循的指导原则是,变量的声明应该与其用途相似。当然,他们可以像数组下标一样将解引用操作符定义为后缀操作符,但他们没有。无论他们为表达式中的运算符位置和优先级选择了什么,都完全定义了声明的结构。@EugeneSh。这是参考资料。Dennis M.Ritchie本人:在第7页,你会发现a)指针/数组/函数运算符确实早于C(来自其无类型的前身),b)他确实定义了声明语法以匹配表达式语法。我同意。我不认为宣言是真正的倒退。对我来说,将声明看作一个整数指针,而不是指向整数的指针(尽管它们在语义上是相同的)是非常有意义的。无论如何,这都是编译器的语法。通常,指针的大小都相同(4到8字节)。从这个意义上说,指针就是指针。编译器只是使用指针类型来验证代码中其他地方的用法。您如何读取声明
char*(*arr)[42]
?我肯定会称之为指向42个字符串指针数组的
指针,
,从内到外读取声明。@cmaster示例表明,这不是向前或向后读取的问题。正确的读取c类型的方法是从内到外,甚至是顺时针,