读复杂的const声明的简单规则?

max*_*zig 42 c c++ const declaration

对于读取复杂指针声明,有左右规则.

但是这条规则没有提到如何阅读const修饰语.

例如,在简单的指针声明中,const可以通过多种方式应用:

char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory
Run Code Online (Sandbox Code Playgroud)

现在用const指针声明指针怎么样?

char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;
Run Code Online (Sandbox Code Playgroud)

阅读这些声明的简单规则是什么?哪些声明有意义?

顺时针/螺旋规则是否适用?

两个真实世界的例子

该方法ASTUnit::LoadFromCommandLine用于const char **提供命令行参数(在llvm clang源中).

参数向量参数的getopt()声明如下:

int getopt(int argc, char * const argv[], const char *optstring);
Run Code Online (Sandbox Code Playgroud)

在这种情况下char * const argv[]等同于何处char * const * argv.

由于两个函数都使用相同的概念(指向字符串的指针向量来提供参数)并且声明不同 - 显而易见的问题是:它们为什么不同?比另一个更有意义吗?

意图应该是:const修饰符应该指定该函数不操纵该向量的字符串并且不改变向量的结构.

Jam*_*nze 64

const修改很简单:它改变了什么之前,除非没有它之前.所以:

char const* buffer;  // const modifies char
char* const buffer;  // const modifies *
Run Code Online (Sandbox Code Playgroud)

等等.一般来说,最好避免使用前面没有任何内容的表单const,但实际上,你会看到它们,所以你必须记住,当没有类型在它之前时const,你必须在逻辑上将它移到第一种类型之后.所以:

const char** buffer;
Run Code Online (Sandbox Code Playgroud)

实际上是:

char const** buffer;
Run Code Online (Sandbox Code Playgroud)

,即指向const char指针的指针.

最后,在函数声明中,[]after读取为*before.(同样,最好避免使用这种误导性符号,但你会看到它,所以你必须处理它.)所以:

char * const argv[],  //  As function argument
Run Code Online (Sandbox Code Playgroud)

是:

char *const * argv,
Run Code Online (Sandbox Code Playgroud)

指向char的const指针的指针.

  • @Vorac一个经常被引用的简化,仅适用于一些简单的案例. (3认同)

max*_*zig 6

(试着关注问题的其他方面)

拇指为const声明的规则是由右至左阅读并const修改了下一个标记.例外:声明开始时const修改前一个标记.

这个例外背后有一个基本原理 - 因为基本声明const char c看起来比一些人更自然char const c- 并且据报道,这种前体形式const char c早于最终的const规则.

getopt的

int getopt(int argc, char * const argv[], const char *optstring);
Run Code Online (Sandbox Code Playgroud)

要么

int getopt(int argc, char * const * argv, const char *optstring);
Run Code Online (Sandbox Code Playgroud)

这意味着它argv是指向非const字符串指针的const向量的指针.

但人们会期待以下声明:

int getopt(int argc, char const * const * argv, const char *optstring);
Run Code Online (Sandbox Code Playgroud)

(指向常量字符串的const向量的指针)

因为getopt()不应该更改通过argv引用的字符串.

至少char **(如使用中main())自动转换为char * const * argv.

ASTUnit::LoadFromCommandLine(...,  const char **argv, ...);
Run Code Online (Sandbox Code Playgroud)

这意味着它argv是指向const字符串的非const const指针数组的指针.

人们会期望const char * const *argv出于与上述相同的原因.

但这更明显,因为char ** 不转换const char **,例如

int main(int argc, char **argv) {
  const char **x = argv; // Compile error!
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

产生编译错误,其中

int main(int argc, char **argv) {
  char * const *x = argv;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

int main(int argc, char **argv) {
  const char * const *x = argv;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

不要.