为什么我不能转换“char**” 到一个“const char* const*” 在C语言中?
以下代码片段(正确地)在 C 中给出警告,在 C++ 中给出错误(分别使用 gcc 和 g++,使用版本 3.4.5 和 4.2.1 进行测试;MSVC 似乎并不关心):
char **a;
const char** b = a;
我可以理解并接受这一点.
此问题的 C++ 解决方案是将 b
更改为 const char * const *
,这不允许重新分配指针并阻止您规避 const 正确性(C++ 常见问题解答)。
char **a;
const char* const* b = a;
但是,在纯C,更正后的版本(使用const char * const *
)仍然给出警告,我不明白为什么。 有没有办法在不使用演员的情况下解决这个问题?
澄清一下:
为什么这会在 C 中生成警告? 它应该是完全常量安全的,并且 C++ 编译器似乎也能识别它。
在说时接受此
char**
作为参数的正确方法是什么(并让编译器强制执行)我不会修改它指向的字符? 例如,如果我想编写一个函数:void f(const char* const* in) { // 只从in读取数据,不写入 }
并且我想在 char**
上调用它,参数的正确类型是什么?
The following code snippet (correctly) gives a warning in C and an error in C++ (using gcc & g++ respectively, tested with versions 3.4.5 and 4.2.1; MSVC does not seem to care):
char **a;
const char** b = a;
I can understand and accept this.
The C++ solution to this problem is to change b
to be a const char * const *
, which disallows reassignment of the pointers and prevents you from circumventing const-correctness (C++ FAQ).
char **a;
const char* const* b = a;
However, in pure C, the corrected version (using const char * const *
) still gives a warning, and I don't understand why.
Is there a way to get around this without using a cast?
To clarify:
Why does this generate a warning in C? It should be entirely const-safe, and the C++ compiler seems to recognize it as such.
What is the correct way to go about accepting this
char**
as a parameter while saying (and having the compiler enforce) that I will not be modifying the characters it points to?
For example, if I wanted to write a function:void f(const char* const* in) { // Only reads the data from in, does not write to it }
And I wanted to invoke it on a char**
, what would be the correct type for the parameter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我很确定 const 关键字并不意味着数据不能更改/是恒定的,只是数据将被视为只读。 考虑一下:
这是有效的代码。 易失性和常量如何共存? 简单的。 易失性告诉编译器在使用数据时始终读取内存,而const告诉编译器在尝试使用serial_port指针写入内存时创建错误。
const 对编译器的优化器有帮助吗? 一点都不。 因为常量可以通过转换添加到数据中或从数据中删除,所以编译器无法确定常量数据是否真的是常量(因为转换可以在不同的翻译单元中完成)。 在 C++ 中,您还可以使用 mutable 关键字来使问题进一步复杂化。
标准中可能根本没有定义当尝试写入真正只读的内存(例如 ROM)时会发生什么。
I'm pretty sure that the const keyword does not imply the data can't be changed/is constant, only that the data will be treated as read-only. Consider this:
which is valid code. How can volatile and const co-exist? Simple. volatile tells the compiler to always read the memory when using the data and const tells the compiler to create an error when an attempt is made to write to the memory using the serial_port pointer.
Does const help the compiler's optimiser? No. Not at all. Because constness can be added to and removed from data through casting, the compiler cannot figure out if const data really is constant (since the cast could be done in a different translation unit). In C++ you also have the mutable keyword to complicate matters further.
What happens when an attempt is made to write to memory that really is read only (ROM, for example) probably isn't defined in the standard at all.
将 char** 隐式转换为 const char * const * 时,至少在 MSVC 14 (VS2k5) 和 g++ 3.3.3 上,我无法收到错误。 GCC 3.3.3 发出警告,我不确定这样做是否正确。
test.c:
编译为 C 代码时输出: cl /TC /W4 /Wp64 test.c
编译为 C++ 代码时输出: cl /TP /W4 /Wp64 test.c
使用 gcc 输出: gcc -Wall test.c
输出为g++: g++ -Wall test.C
无输出
I'm not able to get an error when implicitly casting char** to const char * const *, at least on MSVC 14 (VS2k5) and g++ 3.3.3. GCC 3.3.3 issues a warning, which I'm not exactly sure if it is correct in doing.
test.c:
Output with compile as C code: cl /TC /W4 /Wp64 test.c
Output with compile as C++ code: cl /TP /W4 /Wp64 test.c
Output with gcc: gcc -Wall test.c
Output with g++: g++ -Wall test.C
no output
这很烦人,但如果您愿意添加另一个级别的重定向,通常可以执行以下操作来下推到指针到指针:
它的含义略有不同,但通常是可行的,而且它并不适用。不要使用强制转换。
This is annoying, but if you're willing to add another level of redirection, you can often do the following to push down into the pointer-to-pointer:
It has a slightly different meaning, but it's usually workable, and it doesn't use a cast.
为了被认为是兼容的,源指针在紧接前面的间接级别中应该是 const。 因此,这将在 GCC 中向您发出警告:
但这不会: 或者
,您可以对其进行强制转换:
您将需要相同的强制转换来调用您提到的函数 f() 。 据我所知,在这种情况下没有办法进行隐式转换(C++ 除外)。
To be considered compatible, the source pointer should be const in the immediately anterior indirection level. So, this will give you the warning in GCC:
But this won't:
Alternatively, you can cast it:
You would need the same cast to invoke the function f() as you mentioned. As far as I know, there's no way to make an implicit conversion in this case (except in C++).
你已经发现了问题——这段代码不是常量正确的。 “Const 正确”意味着,除了
const_cast
和删除const
的 C 风格转换之外,您永远不能通过这些 const 指针修改const
对象或参考文献。const
的值 - 正确性 -const
的存在很大程度上是为了检测程序员的错误。 如果您将某些内容声明为const
,则表明您认为不应修改它——或者至少,那些有权访问const
版本的人应该修改它无法修改它。 考虑一下:正如声明的那样,
foo
没有权限修改其参数指向的整数。如果您不确定为什么您发布的代码不是
const
正确的,请考虑以下代码,它与 HappyDude 的代码仅略有不同:非
const
类型只能以特定方式转换为 const 类型,以防止在没有显式强制转换的情况下在数据类型上规避 const。最初声明为 const 的对象特别特殊——编译器可以假设它们永远不会改变。 但是,如果可以在不进行强制转换的情况下为
b
分配a
的值,那么您可能会无意中尝试修改const
变量。 这不仅会破坏您要求编译器进行的检查,禁止您更改该变量值 - 它还会让您破坏编译器优化!在某些编译器上,这将打印
42
,在某些43
上,而在其他编译器上,程序将崩溃。编辑-添加:
HappyDude:您的评论很正确。 C 语言或您使用的 C 编译器对待 const char * const * 的方式与 C++ 语言对待它的方式根本不同。 也许考虑仅对此源代码行静音编译器警告。
You've already identified the problem -- this code is not const-correct. "Const correct" means that, except for
const_cast
and C-style casts removingconst
, you can never modify aconst
object through those const pointers or references.The value of
const
-correctness --const
is there, in large part, to detect programmer errors. If you declare something asconst
, you're stating that you don't think it should be modified -- or at least, those with access to theconst
version only should not be able to modifying it. Consider:As declared,
foo
doesn't have permission to modify the integer pointed to by its argument.If you're not sure why the code you posted isn't
const
-correct, consider the following code, only slightly different from HappyDude's code:Non-
const
types can only convert to const types in particular ways to prevent any circumvention ofconst
on a data-type without an explicit cast.Objects initially declared
const
are particularly special -- the compiler can assume they never change. However, ifb
can be assigned the value ofa
without a cast, then you could inadvertently attempt to modify aconst
variable. This would not only break the check you asked the compiler to make, to disallow you from changing that variables value -- it would also allow you break the compiler optimizations!On some compilers, this will print
42
, on some43
, and others, the program will crash.Edit-add:
HappyDude: Your comment is spot on. Either the C langauge, or the C compiler you're using, treats
const char * const *
fundamentally differently than the C++ language treats it. Perhaps consider silencing the compiler warning for this source line only.几年前我也遇到过同样的问题,这让我一直烦恼不已。
C 中的规则表述更为简单(即,它们没有列出将
char**
转换为const char*const*
等异常情况)。 结果就是,这是不允许的。 在 C++ 标准中,他们包含了更多规则来允许此类情况。归根结底,这只是C标准的问题。 我希望下一个标准(或技术报告)能够解决这个问题。
I had this same problem a few years ago and it irked me to no end.
The rules in C are more simply stated (i.e. they don't list exceptions like converting
char**
toconst char*const*
). Consequenlty, it's just not allowed. With the C++ standard, they included more rules to allow cases like this.In the end, it's just a problem in the C standard. I hope the next standard (or technical report) will address this.