对于读取复杂指针声明,有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
修饰符应指定该函数不操作此向量的字符串,并且不会更改向量的结构。
答案 0 :(得分:61)
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指针的指针。
答案 1 :(得分:6)
(试着关注问题的其他方面)
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 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;
}
不要。