2008-09-16 114 views
55

下面的代码段(正确地)给出在C语言的警告和错误在C++(使用gcc &克++分别与3.4.5和4.2.1版本测试; MSVC似乎并不关心):为什么我不能在C中将'char **'转换为'const char * const *'?

char **a; 
const char** b = a; 

我可以理解并接受这一点。
此问题的C++解决方案是将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 **,什么是正确的类型参数?

编辑: 非常感谢那些已经回复的人,特别是那些回答问题和/或跟进我的回复的人。

我已经接受了答案,即我不想在没有演员的情况下做我想做的事,不管它是否应该是可能的。

+0

我对你的问题感到困惑,是这样的:“我如何让C不警告我?”还是“我如何让C++不会抛出编译错误?”或者,也许它们都不是这些。 – user7116 2008-09-16 22:55:12

+0

我同意sixlettervariables,这个问题需要进一步澄清。 – 2008-09-16 23:00:18

+0

问题是“为什么我不能将'char **'转换为'char * const *?' – Kevin 2008-09-16 23:05:53

回答

53

几年前,我也遇到了同样的问题,它让我感到无法接受。

C中的规则更简单地陈述(即,它们没有列出例如将char**转换为const char*const*的例外)。结果,这只是不被允许的。在C++标准中,它们包含了更多的规则来允许这样的情况。

最后,这只是C标准中的一个问题。我希望下一个标准(或技术报告)能解决这个问题。

11

>然而,在纯C,这仍然给出了一个警告,我不明白为什么

你已经发现了问题 - 这个代码是不是常量,正确的。 “Const correct”意思是说,除了const_cast和C-style强制删除const之外,你永远不能通过这些const指针或引用来修改一个const对象。

常量正确性的值 - const在很大程度上是为了检测程序员错误。如果你将某些东西声明为const,那么你就说你不认为它应该被修改 - 或者至少,那些有权访问const版本的人不应该修改它。试想一下:

void foo(const int*); 

至于宣布,富没有许可修改整数通过它的参数指向。

如果你不知道你为什么发布的代码不是const的,正确的,考虑下面的代码,仅从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; 

非const类型只能转换为常量以特定的方式来防止在没有明确强制转换的情况下对数据类型的'const'进行规避。

最初声明const的对象特别特别 - 编译器可以假定它们永远不会改变。然而,如果'b'可以在没有强制转换的情况下分配'a'的值,那么你可能会不经意地尝试修改一个const变量。这不仅会中断您要求编译器进行的检查,不允许您更改该变量值 - 它还会允许您中断编译器优化!

在某些编译器上,这将打印'42',在某些'43'和其他文件上,程序将崩溃。

编辑相加:

HappyDude:您的评论是即期。无论是C语言还是您使用的C编译器,对待const char * const *的处理方式都与C++语言的处理方式根本不同。也许可以考虑只沉默这个源代码行的编译器警告。

编辑,删除:删除错字

0

我不能够得到一个错误,当隐式铸造焦炭**为const char * const的*,至少在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 

输出与克++:克++ -Wall TEST.C

没有输出

0

我很肯定的是,关键字const并不意味着该数据不能被改变/是恒定的,只有数据将被视为只读。考虑这个:

const volatile int *const serial_port = SERIAL_PORT; 

这是有效的代码。 volatile和const如何共存?简单。 volatile指示编译器在使用数据时总是读取内存,而const在使用serial_port指针尝试写入内存时告诉编译器创建错误。

const是否帮助编译器的优化器?一点都不。因为通过强制转换可以将常量添加到数据中或从中删除,因此编译器无法弄清楚const数据是否真的是常量(因为可以在不同的翻译单元中进行强制转换)。在C++中,你也有可变关键字使事情进一步复杂化。

char *const p = (char *) 0xb000; 
//error: p = (char *) 0xc000; 
char **q = (char **)&p; 
*q = (char *)0xc000; // p is now 0xc000 

时试图写这确实是只读(ROM,例如)内存会发生什么可能未在标准中定义的。

9

要被认为是兼容的,源指针应该是在紧邻前间接级别的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++除外)。

1

这是恼人的,但如果你愿意加入重定向的另一个层面上,你可以经常下向下推入指针到指针:

char c = 'c'; 
char *p = &c; 
char **a = &p; 

const char *bi = *a; 
const char * const * b = &bi; 

它有一个稍微不同意思是,但它通常是可行的,并且它不使用演员。

相关问题