为了读取复杂的指针声明,有right-left rule。
但是这条规则没有提到如何阅读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
那么使用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;
阅读这些声明的简单规则是什么?哪些声明有意义?
方法ASTUnit::LoadFromCommandLine
使用const char **
提供命令行参数(在llvm clang源中)。
getopt()
的参数向量参数声明如下:
int getopt(int argc, char * const argv[], const char *optstring);
在这种情况下,char * const argv[]
相当于char * const * argv
。
由于两个函数都使用相同的概念(指向字符串的指针向量来提供参数)并且声明不同 - 显而易见的问题是:它们为什么不同?比另一个更有意义吗?
意图应该是:const
修饰符应该指定该函数不操纵该向量的字符串并且不改变向量的结构。
const
修饰符是微不足道的:它修改了它之前的内容,除非在它之前没有任何内容。所以:
char const* buffer; // const modifies char
char* const buffer; // const modifies *
等等。一般来说,最好避免在const
之前没有任何形式的形式,但在实践中,你会看到它们,所以你必须记住,当没有类型在const
之前,你必须在逻辑上将它移动到第一种。所以:
const char** buffer;
实际上是:
char const** buffer;
,即指向const char指针的指针。
最后,在函数声明中,[]
之后读作*
。 (同样,最好避免使用这种误导性符号,但你会看到它,所以你必须处理它。)所以:
char * const argv[], // As function argument
是:
char *const * argv,
指向char的const指针的指针。
(试着关注问题的其他方面)
rule of thumb for const declarations是从右到左阅读它们,const
修改下一个标记。例外:在声明开始时,const
修改前一个标记。
有一个rationale behind this exception - 对于基本声明const char c
寻找一些比char const c
更自然的人 - 据报道,const char c
的前体形式早于最终的const规则。
int getopt(int argc, char * const argv[], const char *optstring);
要么
int getopt(int argc, char * const * argv, const char *optstring);
这意味着argv
是指向非const字符串指针的const向量的指针。
但人们会期待以下声明:
int getopt(int argc, char const * const * argv, const char *optstring);
(指向常量字符串的const向量的指针)
因为getopt()
不应该改变通过argv引用的字符串。
至少char **
(在main()
中使用)自动转换为char * const * argv
。
ASTUnit::LoadFromCommandLine(..., const char **argv, ...);
这意味着argv
是指向const字符串的非const const指针数组的指针。
由于与上述相同的原因,人们会再次期待const char * const *argv
。
但这更为明显,因为char **
does not convert到const char **
,例如
int main(int argc, char **argv) {
const char **x = argv; // Compile error!
return 0;
}
产生编译错误,其中
int main(int argc, char **argv) {
char * const *x = argv;
return 0;
}
和
int main(int argc, char **argv) {
const char * const *x = argv;
return 0;
}
不要。