Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C语言中,常量变量可以通过指针修改吗?_C_Pointers_Constants - Fatal编程技术网

在C语言中,常量变量可以通过指针修改吗?

在C语言中,常量变量可以通过指针修改吗?,c,pointers,constants,C,Pointers,Constants,我在代码中写了一些类似的东西 const int x=1; int *ptr; ptr = &x; *ptr = 2; 这对所有编译器都有效吗?为什么GCC编译器没有注意到我们正在更改一个常量变量?糟糕的程序员。没有月饼 如果需要修改常量,请将其复制到非常量变量,然后使用它。这是有原因的。试图“偷偷”绕过常量可能会导致严重的运行时问题。i、 e.优化器可能使用了内联值等 const int x=1; int non_const_x = x; non_const_x = 2; 这里有一

我在代码中写了一些类似的东西

const int x=1;
int *ptr;
ptr = &x;
*ptr = 2;

这对所有编译器都有效吗?为什么GCC编译器没有注意到我们正在更改一个常量变量?

糟糕的程序员。没有月饼

如果需要修改常量,请将其复制到非常量变量,然后使用它。这是有原因的。试图“偷偷”绕过常量可能会导致严重的运行时问题。i、 e.优化器可能使用了内联值等

const int x=1;
int non_const_x = x;
non_const_x = 2;

这里有一个很好的讨论:

我希望gcc能够编译此文件,因为:

  • ptr被允许指向x,否则读取它将是不可能的,尽管正如下面的评论所说,它不是非常出色的代码,编译器应该抱怨。警告选项(我猜)会影响它是否真的被警告过
  • 当您写入x时,编译器不再“知道”它正在写入常量,所有这些都在C中的程序员手中。但是,它确实知道,因此它可能会根据您选择的警告选项向您发出警告

然而,它是否有效将取决于代码的编译方式、所选编译选项的const实现方式以及目标CPU和体系结构。这可能有用。或者它可能会崩溃。或者,你可能会写入一个“随机”内存位,并导致(或不是)一些反常的效果。这不是一个好的编码策略,但这不是你的问题:-)

const
实际上并不意味着“常量”。C语言中的“常量”有一个在编译时确定的值;文字
42
就是一个例子。
const
关键字实际上意味着只读。例如,考虑:

const int r = rand();
直到程序执行时,
r
的值才确定,但是
const
关键字意味着在初始化
r
后不允许修改它

在代码中:

const int x=1;
int *ptr;
ptr = &x;
*ptr = 2;
赋值
ptr=&x
是一种违反约束的行为,这意味着要求符合条件的编译器对此进行投诉;您不能合法地将
const int*
(指向const int的指针)值分配给非const
int*
对象。如果编译器生成一个可执行文件(它不需要这样做;它可以拒绝它),那么该行为不由C标准定义

例如,生成的代码可能实际将值
2
存储在
x
中,但随后对
x
的引用可能会产生值
1
,因为编译器知道
x
在初始化后不能被修改。它知道,因为你告诉它,通过定义
x
const
。如果你对编译器撒谎,后果可能是非常糟糕的

实际上,可能发生的最糟糕的事情是程序的行为与您期望的一样;这意味着你有一个很难发现的bug。(但你应该得到的诊断结果将是一个很大的线索。)

:

6.7.3类型鉴定人 …
6如果试图通过使用修改限定类型的对象 对于具有非常量限定类型的左值,行为是未定义的。如果尝试失败 指通过使用左值定义为易变定性类型的对象 对于非挥发性定性类型,行为未定义。133)
133)这适用于那些行为类似于被限定为合格类型的对象,即使它们是 从未实际定义为程序中的对象(如内存映射输入/输出处的对象 地址)。 重点补充

由于行为未定义,编译器不需要发出诊断,也不需要停止转换。这在一般情况下很难抓住;假设你有一个函数,比如

void foo( int *p ) { *p = ...; }
在它自己的独立翻译单元中定义。在翻译过程中,编译器无法知道
p
是否指向
const
限定的对象。如果你的电话是

const int x;
foo( &x );
您可能会收到类似“foo”丢弃限定符的
参数1的警告或类似的提示


还要注意,
const
限定符并不一定意味着相关变量将存储在只读内存中,因此上面的代码可能会“工作”(更新
x
中的值),因为您可以通过围绕
const
语义进行结束运行来成功更新
x
。但是,您也可以不将
x
声明为
const

是的。您应该会收到这样一条消息,如
warning:assignment丢弃指针目标类型中的限定符
,参考行
ptr=&x。这也有一些信息:假设编译器可以将
常量int
放入只读内存。然后
*ptr=2将崩溃。事实上,不要指望它会崩溃。哦,编译器会抱怨在
ptr=&x;上丢弃了限定符ptr=&x不兼容类型'int*'和'const int*@BillHicks和我曾经被刀刺伤但没有死。。。这证明了刺伤不是致命的吗?
ptr
不允许指向
x
;编译器应该(而且确实)抱怨。要使赋值有效,您需要
const int*ptr
。如果您需要修改
const
(非常量)对象,首先不要将其定义为
const
。在我们讨论6.7.3/6之前,最好还提一下OP的代码是违反约束的。(参考号为C116.5.4/3)标准参考号:C116.5.4/3