为什么我不能在C中将'char **'转换为'const char * const *'?
下面的代码片段(正确)给出了C中的警告和C ++中的错误(分别使用gcc&g ++,在版本3.4.5和4.2.1中testing; MSVC似乎不在乎):
char **a; const char** b = a;
我可以理解并接受这一点。
这个问题的C ++解决scheme是将b改为const char * const *,它不允许重新分配指针,并且阻止你规避const正确性( C ++ FAQ )。
char **a; const char* const* b = a;
但是,在纯C中,修正后的版本(使用const char * const *)仍然会给出警告,我不明白为什么。 有没有办法解决这个问题,而不使用一个演员?
澄清:
1)为什么这会在C中产生警告? 它应该完全是常量安全的,C ++编译器似乎也是这样认识的。
2)接受这个char **作为参数的正确方法是什么?在说(并且让编译器强制执行)的时候我不会修改它指向的字符? 例如,如果我想写一个函数:
void f(const char* const* in) { // Only reads the data from in, does not write to it }
我想在char **上调用它,参数的正确types是什么?
编辑:感谢那些已经回复的人,特别是那些回答问题和/或跟进我的回应的人。
我已经接受了这样一个答案,即不pipe没有演员,我想做的事情都是不可能完成的,不pipe是否可能。
几年前,我也遇到了同样的问题,这让我感到无法自拔。
在C中的规则更简单地陈述(即他们不列出例如转换char**
为const char*const*
exception)。 结果,这是不允许的。 在C ++标准中,他们包含了更多的规则来允许这样的情况。
最后,这只是C标准中的一个问题。 我希望下一个标准(或技术报告)能解决这个问题。
>然而,在纯粹的C,这仍然给出警告,我不明白为什么
你已经发现了这个问题 – 这个代码不是const正确的。 “Const correct”意思是,除了const_cast和C-style强制删除const之外,你永远不能通过这些const指针或引用来修改一个const对象。
常量正确性的值const在很大程度上是为了检测程序员错误。 如果你将某些东西声明为const,那么你就说你不认为它应该被修改,或者至less那些只能访问const版本的应该不能修改它。 考虑:
void foo(const int*);
正如所声明的,foo没有修改其参数指向的整数的权限 。
如果您不确定为什么您发布的代码不是常量不正确,请考虑以下代码,与HappyDude的代码略有不同:
char *y; char **a = &y; // a points to y const char **b = a; // now b also points to y // const protection has been violated, because: const char x = 42; // x must never be modified *b = &x; // the type of *b is const char *, so set it // with &x which is const char* .. // .. so y is set to &x... oops; *y = 43; // y == &x... so attempting to modify const // variable. oops! undefined behavior! cout << x << endl;
非常量types只能以特定的方式转换为常量types,以防止在没有显式强制转换的情况下规避数据types的“常量”。
最初声明const的对象特别特别 – 编译器可以假定它们永远不会改变。 但是,如果'b'可以被赋值为'a'而没有强制转换,那么你可能会不小心尝试修改一个constvariables。 这不仅会中断你要求编译器做的检查,而且不允许你改变这个variables的值 – 这也会让你打破编译器的优化!
在某些编译器上,这将打印“42”,在某些“43”和其他文件上,程序将崩溃。
编辑补充:
HappyDude:您的评论是现货。 你使用的C语言或者C编译器,对待const char * const *与C ++语言对待它基本上是不同的。 也许可以考虑只沉默这个源码行的编译器警告。
编辑 – 删除:删除错字
为了被认为是兼容的,源指针应该是在前面的间接层次上的const。 所以,这会给你在GCC的警告:
char **a; const char* const* b = a;
但是这不会:
const char **a; const char* const* b = a;
或者,你可以投它:
char **a; const char* const* b = (const char **)a;
您将需要相同的强制转换来调用函数f(),如您所述。 据我所知,在这种情况下没有办法进行隐式转换(C ++除外)。
这很烦人,但是如果你愿意添加另一个redirect级别,你通常可以做下面的事情来下压指针指针:
char c = 'c'; char *p = &c; char **a = &p; const char *bi = *a; const char * const * b = &bi;
它有一个稍微不同的含义,但它通常是可行的,它不使用演员。
当隐式将char **转换为const char * const *,至less在MSVC 14(VS2k5)和g ++ 3.3.3上时,我无法得到一个错误。 GCC 3.3.3发出警告,我不确定它是否正确。
test.c的:
#include <stdlib.h> #include <stdio.h> void foo(const char * const * bar) { printf("bar %s null\n", bar ? "is not" : "is"); } int main(int argc, char **argv) { char **x = NULL; const char* const*y = x; foo(x); foo(y); return 0; }
以C代码编译输出:cl / TC / W4 / Wp64 test.c
test.c(8) : warning C4100: 'argv' : unreferenced formal parameter test.c(8) : warning C4100: 'argc' : unreferenced formal parameter
用C ++代码编译输出:cl / TP / W4 / Wp64 test.c
test.c(8) : warning C4100: 'argv' : unreferenced formal parameter test.c(8) : warning C4100: 'argc' : unreferenced formal parameter
用gcc输出:gcc -Wall test.c
test2.c: In function `main': test2.c:11: warning: initialization from incompatible pointer type test2.c:12: warning: passing arg 1 of `foo' from incompatible pointer type
用g ++输出:g ++ -Wall test.C
没有输出
我很确定,const关键字并不意味着数据不能被改变/是不变的,只是数据将被视为只读。 考虑这个:
const volatile int *const serial_port = SERIAL_PORT;
这是有效的代码。 volatile和const怎么能并存? 简单。 volatile指示编译器在使用数据时总是读取内存,而当使用serial_port指针尝试写入内存时,const告诉编译器创build一个错误。
const是否帮助编译器的优化器? 一点都不。 因为通过强制转换可以将常量添加到数据中或从中删除,编译器无法确定const数据是否真的是常量(因为可以在不同的转换单元中执行强制转换)。 在C ++中,你也有可变关键字使事情进一步复杂化。
char *const p = (char *) 0xb000; //error: p = (char *) 0xc000; char **q = (char **)&p; *q = (char *)0xc000; // p is now 0xc000
当尝试写入真正只读的内存(例如ROM)时,会发生什么情况可能在标准中没有定义。