下面的代码片段(正确地)在C中给出了一个警告,在C++中给出了一个错误(分别使用gcc & g ++,用版本3. 4. 5和4. 2. 1测试;MSVC似乎并不在意):
char **a;
const char** b = a;
我可以理解和接受。
这个问题的C解决方案是将b
更改为const char * const *
,这样就不允许重新分配指针,并防止您绕过常量正确性(C FAQ)。
char **a;
const char* const* b = a;
然而,在纯C中,修正后的版本(使用const char * const *
)仍然会给出警告,我不明白为什么。有没有办法不使用强制类型转换就能解决这个问题?
澄清:
1.为什么这会在C中生成警告?它应该是完全常量安全的,并且C++编译器似乎可以识别它。
1.接受char**
作为参数,同时声明(并让编译器强制执行)我不会修改它所指向的字符,正确的方法是什么?例如,如果我想写一个函数:
void f(const char* const* in) {
// Only reads the data from in, does not write to it
}
我想在char**
上调用它,那么参数的正确类型是什么呢?
6条答案
按热度按时间uxhixvfz1#
几年前我也遇到过同样的问题,它让我烦恼不已。
C中的规则表述得更简单(例如,它们没有列出将
char**
转换为const char*const*
这样的例外)。因此,这是不允许的。随着C++标准的出现,它们包含了更多的规则来允许这样的情况。说到底,这只是C标准中的一个问题,我希望下一个标准(或技术报告)会解决这个问题。
jgwigjjp2#
要考虑兼容性,源代码指针应该是const,位于前一个间接层。因此,这会在GCC中给予你一个警告:
但这不会:
或者,您可以将其转换为:
调用函数f()需要相同的类型转换,据我所知,在这种情况下没有隐式转换的方法(C++除外)。
c8ib6hqw3#
但是,在纯C中,这仍然会给出警告,我不明白为什么
您已经发现了问题所在--这段代码不是常量正确的。“常量正确”意味着,除了
const_cast
和删除const
的C样式强制转换之外,您永远不能通过这些常量指针或引用修改const
对象。const
-correction--const
的值在很大程度上是为了检测程序员的错误。如果您将某个东西声明为const
,则表示您认为不应该修改它--或者至少,那些只能访问const
版本的用户不应该修改它。请考虑以下问题:正如声明的那样,
foo
没有修改其参数所指向的整数的 * 权限 *。如果您不确定为什么您发布的代码不正确,请考虑以下代码,与HappyDude的代码仅略有不同:
非
const
类型只能以特定的方式转换为常量类型,以防止在没有显式强制转换的情况下对数据类型进行任何const
规避。最初声明为
const
的对象特别特殊--编译器可以假定它们永远不会更改。然而,如果b
可以被赋值为a
而无需强制转换,那么您可能会无意中试图修改const
变量。这不仅会破坏您要求编译器进行的检查,不允许您更改变量值--这也将允许您破坏编译器优化!在某些编译器上,这将打印
42
,在某些43
上,程序将崩溃。编辑-添加:
HappyDude:你的评论说得很对。无论是C语言,还是你使用的C编译器,对待
const char * const *
的方式都与 C++ 有根本的不同。也许可以考虑只对这一行代码关闭编译器警告。yvgpqqbh4#
这很烦人,但是如果您愿意添加另一个级别的重定向,通常可以执行以下操作来向下推到指针到指针:
它的含义略有不同,但通常是可行的,并且不使用强制类型转换。
jhkqcmku5#
至少在MSVC 14(VS 2k 5)和g++ 3.3.3上,当隐式地将char**转换为const char * const * 时,我不能得到一个错误。GCC 3.3.3发出一个警告,我不确定它是否正确。
试验c:
编译为C代码的输出:cl /TC /W 4/Wp 64试验c
编译为C++代码的输出:cl /TP /W 4/Wp 64试验c
使用gcc的输出:gcc -壁厚试验c
g的输出:g -壁厚试验. C
6yoyoihd6#
我很确定const关键字并不意味着数据不能被改变或者是常量,只是意味着数据将被视为只读。
volatile和const如何共存?很简单,volatile告诉编译器在使用数据时总是读取内存,const告诉编译器在试图使用serial_port指针写入内存时创建错误。
const对编译器的优化有帮助吗?没有。一点也没有。因为constness可以通过强制转换添加到数据中或从数据中删除,所以编译器无法判断const数据是否真的是常量(因为强制转换可以在不同的翻译单元中完成)。在C++中,您还可以使用mutable关键字来使问题进一步复杂化。
当试图写入实际上是只读的内存(例如ROM)时会发生什么,可能根本没有在标准中定义。