以下代码段(正确)在C中给出了警告,并在C ++中给出了错误(分别使用经版本3.4.5和4.2.1测试的gcc和g ++; MSVC似乎无关紧要):

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语言中生成警告? 它应该完全是const安全的,C ++编译器似乎也是如此。
2)在说(并让编译器强制执行)我不会修改其指向的字符时接受此char **作为参数的正确方法是什么? 例如,如果我想编写一个函数:

void f(const char* const* in) {
  // Only reads the data from in, does not write to it
}

我想在char **上调用它,参数的正确类型是什么?

===============>>#1 票数:58 已采纳

几年前,我遇到了同样的问题,这让我无休止。

C语言中的规则更简单地声明(即,它们未列出将char**转换为const char*const*异常)。 因此,这是不允许的。 在C ++标准中,它们包括更多的规则以允许这样的情况。

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

===============>>#2 票数:10

但是,在纯C语言中,这仍然会发出警告,我不明白为什么

您已经确定了问题-此代码不是const正确的。 “正确的常量”意味着,除了const_cast和C样式强制类型转换删除const ,您永远无法通过这些const指针或引用来修改const对象。

const -correctness - const是存在的,在很大程度上,检测编程错误。 如果您将某些内容声明为const ,则表示您不应该对其进行修改,或者至少,那些只能访问const版本的用户不能对其进行修改。 考虑:

void foo(const int*);

如所声明的, foo没有权限修改其参数所指向的整数。

如果不确定为什么发布的代码不是const -correct,请考虑以下代码,该代码与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规避。

最初声明为const对象特别特殊-编译器可以假定它们永不更改。 然而,如果b可以分配的值a不进行强制转换,那么你可能无意中试图修改一个const变量。 这不仅会破坏您要求编译器进行的检查,不允许您更改该变量的值,还会使您破坏编译器的优化!

在某些编译器上,这将打印42 ,在某些编译器上,则打印43 ,而在其他编译器上,该程序将崩溃。

编辑添加:

HappyDude:您的评论很对。 无论是C语言还是正在使用的C编译器,对const char * const *根本不同于C ++语言。 也许可以考虑仅对此源代码行禁用编译器警告。

===============>>#3 票数:10

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

===============>>#4 票数:1

这很烦人,但是如果您愿意添加另一级别的重定向,则通常可以执行以下操作以向下推入指针到指针:

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

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

它的含义略有不同,但是通常是可行的,并且不使用强制转换。

===============>>#5 票数:0

至少在MSVC 14(VS2k5)和g ++ 3.3.3上将char **隐式转换为const char * const *时,我无法出错。 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

没有输出

===============>>#6 票数:0

我很确定const关键字并不意味着数据不能被更改/是恒定的,只是数据将被视为只读。 考虑一下:

const volatile int *const serial_port = SERIAL_PORT;

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

const是否有助于编译器的优化器? 一点都不。 由于可以通过强制转换将常量添加到数据中或从数据中删除常量,因此编译器无法确定const数据是否确实是常量(因为强制转换可以在其他转换单元中完成)。 在C ++中,您还可以使用mutable关键字使事情进一步复杂化。

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

尝试写入真正只读的内存(例如ROM)时会发生什么,可能根本没有在标准中定义。

  ask by community wiki translate from so

未解决问题?本站智能推荐:

7回复

const-correctness是否为编译器提供了更多优化空间?

我知道它可以提高可读性并使程序不易出错,但是它可以在多大程度上提高性能呢? 另外,引用和const指针之间的主要区别是什么? 我假设它们以不同的方式存储在内存中,但是怎么办呢?
1回复

使用指向const数据的指针的替代方法?

在我的C99程序中,我有一个带有指向浮点数的指针的结构(表示矩阵)。 该结构经过一组例程,例如,从main调用。 我想确保调用的例程不会改变结构的内容(矩阵中的实际值)。 但是,数据应该可以从main更改。 我提出了以下解决方案,其中定义了一个指向const数据的指针:
5回复

为什么将“指向非const的指针”转换为“指向const的指针”是不合法的

将指向非常量的指针转换为指向const的指针是合法的。 那么,为什么是不是合法的指针转换成指向非const的指针指向常量 ? 例如,以下代码为何非法:
2回复

指向指针的c ++ const

指向常量int的指针。 我可以更改指针,但不能更改值: 指向int的常量指针。 我可能不会更改指针,但可能会更改变量的值: 现在,如果我正在处理指向指针的指针,情况会如何? 我如何: a)声明一个指向非常量int的const指针 b)声明一个指向非常量in
1回复

在函数原型中将/ * const * /而不是const限定符添加到char * param

我正面临一个函数,它接受一个char数组的指针,但它只对char *指向的mem执行读操作。 我可以在char *参数之前直接将const添加到原型中,但这会破坏其他非常量正确的代码。 我决定添加注释/*const*/来表示该函数只执行读操作。 然而,这让我的同事感到困惑,我想知道
2回复

const使用std :: unique_ptr / std :: shared_ptr正确合成

目前,我想知道如何正确使用std::unique_ptr作为有关const正确性的成员变量。 下面的示例允许将my_foo拥有的内容更改为const: std::make_unique<T>用std::make_unique<const T>替换std::m
2回复

我可以将const char *数组传递给execv吗?

这是execv的原型: 我可以将const char指针数组作为第二个参数传递吗? 当未设置USE_CAST时,此示例程序给出警告: 编译时,如果我不使用强制类型转换,gcc会说“从不兼容的指针类型传递'execv'的参数2”。 从execv的POSIX文档 (在“基
2回复

是什么意思'char const * const c =“”'[复制]

这个问题在这里已有答案: const int *,const int * const和int const *之间有什么区别? 17个答案 这是什么意思? 它与指针声明一样吗? 请有人解释一下。 先感谢您!
3回复

从const方法对成员调用nonconst方法

我惊讶地发现“const”中的这个“漏洞”: 因此,基本上从const方法B::go() ,如果指针引用了类型A对象,则可以调用非const成员函数(恰当地命名为nonconst() )。 这是为什么? 看起来像一个问题(它在我的代码中,我找到了它。)
3回复

为什么我可以调用从const方法更改成员的方法?

我不确定为什么我可以通过const方法修改对象,请看: #include <iostream> struct Foo { int a = 0; void change() { a = 3; } }; struct Test { F