我们可以通过指针来改变const定义的对象的值吗?
#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
它会起作用吗?
#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
Will it work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
这是“未定义的行为”,这意味着根据标准,您无法预测尝试此操作时会发生什么。它可能会根据特定的机器、编译器和程序状态执行不同的操作。
在这种情况下,最常发生的情况是答案是“是”。变量,无论是否为常量,都只是内存中的一个位置,您可以打破常量规则并简单地覆盖它。 (当然,如果程序的其他部分依赖于其 const 数据是常量,这将导致严重的错误!)
但是在某些情况下 - 最典型的是 const static 数据 - 编译器可能会将此类变量放入内存的只读区域。例如,MSVC 通常将 const static int 放入可执行文件的 .text 段中,这意味着如果您尝试对其进行写入,操作系统将引发保护错误,并且程序将崩溃。
在编译器和机器的其他组合中,可能会发生完全不同的情况。您可以肯定预测的一件事是,这种模式会惹恼任何必须阅读您的代码的人。
It's "undefined behavior," meaning that based on the standard you can't predict what will happen when you try this. It may do different things depending on the particular machine, compiler, and state of the program.
In this case, what will most often happen is that the answer will be "yes." A variable, const or not, is just a location in memory, and you can break the rules of constness and simply overwrite it. (Of course this will cause a severe bug if some other part of the program is depending on its const data being constant!)
However in some cases -- most typically for
const static
data -- the compiler may put such variables in a read-only region of memory. MSVC, for example, usually puts const static ints in .text segment of the executable, which means that the operating system will throw a protection fault if you try to write to it, and the program will crash.In some other combination of compiler and machine, something entirely different may happen. The one thing you can predict for sure is that this pattern will annoy whoever has to read your code.
这是未定义的行为。证明:
并运行它。输出将为 70 (gcc 4.3)
然后像这样编译它:
并运行它。输出将为 12。当它进行优化时,编译器可能会将 12 加载到寄存器中,并且当它需要访问 printf 的 a 时不会再次加载它,因为它“知道”a 无法更改。
It's undefined behaviour. Proof:
and run it. Output will be 70 (gcc 4.3)
Then compile it like this:
and run it. The output will be 12. When it does optimisation, the compiler presumably loads 12 into a register and doesn't bother to load it again when it needs to access a for the printf because it "knows" that a can't change.
通过指针修改 const 限定对象会调用未定义的行为,这就是结果。它可能是您期望从特定实现中获得的东西,例如,如果已将其放置在
.text
中,则先前的值保持不变,等等。Modifying a
const
qualified object through a pointer invokes undefined behaviour, and such is the result. It may be something you'd expect from a particular implementation, e.g. the previous value unchanged, if it has been placed in.text
, etc.它确实可以与 gcc 一起使用。但它不喜欢它:
但执行时值确实发生了变化。我不会指出明显的禁忌...
It does indeed work with gcc. It didn't like it though:
But the value did change when executed. I won't point out the obvious no-no...
是的,您可以使用这样的代码来完成它。但当
a
是全局时,代码不适用(gcc编译的程序给了我分段错误
。)一般来说,在心爱的C中,你几乎总能找到某种方法破解不应该改变或暴露的东西。 const 这里就是一个例子。
但考虑到可怜的人(也许是 6 个月后的我自己)维护我们的代码,我经常选择不这样做。
yes, you can make it done by using such code. but the code do not apply when when
a
is global (a gcc-compiled program gave mesegmentation fault
.)generally speaking, in beloved C, you can almost always find someway to hack things that are not supposed to be changed or exposed. const here being a example.
But thinking about the poor guy(maybe myself after 6 months) maintains our code, I often choose not do so.
这里指针
p
的类型是int*
,它被赋以const int*
类型的值 (&a< /code> => const int 变量的地址)。
隐式强制转换消除了常量性,尽管 gcc 会抛出警告(请注意,这很大程度上取决于实现)。
由于指针未声明为 const,因此可以使用此类指针更改值。
如果指针被声明为 const int* p = &a ,您将无法执行 *p = 70 。
Here the type of pointer
p
isint*
, which is being assigned the value of typeconst int*
(&a
=> address of aconst int
variable).Implicit cast eliminates the constness, though gcc throws a warning (please note this largely depends on the implementation).
Since the pointer is not declared as a
const
, value can be changed using such pointer.if the pointer would be declared as
const int* p = &a
, you won't be able to do*p = 70
.此代码包含约束违规:
违反的约束是 C11 6.5.16.1/1“简单赋值”;如果两个操作数都是指针,则左侧指向的类型必须具有右侧指向的类型的所有限定符。 (并且没有限定符的类型必须兼容)。
因此违反了约束,因为
&a
的类型为const int *
,该类型以const
作为限定符;但该限定符不会出现在p
类型中,即int *
。编译器必须发出诊断信息,并且可能不会生成可执行文件。任何可执行文件的行为都是完全未定义的,因为程序不遵守语言规则。
This code contains a constraint violation:
The constraint violated is C11 6.5.16.1/1 "Simple assignment"; if both operands are pointers then the type pointed to by the left must have all the qualifiers of the type pointed to by the right. (And the types, sans qualifiers, must be compatible).
So the constraint is violated because
&a
has typeconst int *
, which hasconst
as a qualifier; but that qualifier does not appear in the type ofp
which isint *
.The compiler must emit a diagnostic and might not generate an executable. The behaviour of any executable would be completely undefined, since the program does not comply with the rules of the language.
您不能使用指向常量变量的指针来更改常量变量的值。这种类型的指针称为
指向常量的指针
。还有另一个概念,称为常量指针。这意味着一旦指针指向一个内存位置,就无法使其指向另一个位置。
You cannot change the value of a constant variable by using a pointer pointing to it. This type of pointer is called as
Pointer to a constant
.There is also another concept called
Constant Pointer
. It means that once a pointer points to a memory location you cannot make it point to the another location.坏主意,坏主意。
此外,该行为是特定于平台和实现的。如果您运行的平台上常量存储在不可写内存中,则这显然不起作用。
而且,你到底为什么要这么做?更新源中的常量,或将其设为变量。
Bad, BAD idea.
Also, the behavior is platform- and implementation-specific. If you're running on a platform where the constant is stored in non-writable memory, this obviously won't work.
And, why on earth would you want to? Either update the constant in your source, or make it a variable.
更改 const 变量值的问题是编译器不会期望发生这种情况。考虑这段代码:
为什么编译器会在最后一条语句中读取
a
?编译器知道a
是12
,并且由于它是const
,所以它永远不会改变。因此优化器可能会将上面的代码转换成这样:这可能会导致奇怪的问题。例如,代码可能在没有优化的调试版本中按预期工作,但在经过优化的发布版本中会失败。
实际上,一个好的优化器可能会将整个代码转换为这样:
因为之前的所有其他代码在编译器看来没有任何效果。省略没有效果的代码也不会对整个程序产生影响。
另一方面,一个像样的编译器会识别出您的代码有错误并警告您,因为
实际上是错误的。正确的是:
因为
p
不是指向int
的指针,它是指向const int
的指针,当这样声明时,下一行将导致硬编译错误。要消除警告,您必须进行强制转换:
更好的编译器会认识到此强制转换破坏了 const 承诺,并指示优化器不要将 a 视为 <代码>常量。
正如您所看到的,编译器的质量、功能和设置将最终决定您可以期望的行为。这意味着相同的代码在不同平台上或在同一平台上使用不同编译器时可能会显示不同的行为。
如果 C 标准为这种情况定义了一种行为,那么所有编译器都必须实现它,无论标准定义了什么,它都很难实现,这给每个想要编写编译器的人带来了巨大的负担。即使标准只是说“这是禁止的”,所有编译器都必须执行复杂的数据流分析来执行此规则。所以标准并没有定义它。它定义了
const
值不能更改,如果您找到一种方法来更改它们,则没有任何行为可以依赖。The problem with changing the value of
const
variable is that the compiler will not expect that to happen. Consider this code:Why would the compiler read
a
in the last statement? The compiler knows thata
is12
and since it isconst
, it will never change. So the optimizer may transform the code above into this:This can lead to strange issues. E.g. the code might work as desired in debug builds without optimization but it will fail in release builds with optimization.
Actually a good optimizer might transform the entire code to this:
As all other code before has no effect in the eye of the compiler. Leaving out code that has no effect will also have no effect on the overall program.
On the other hand, a decent compiler will recognize, that your code is faulty and warn you, since
is actually wrong. Correct would be:
as
p
is not a pointer toint
, it is a pointer toconst int
and when declared like that, the next line will cause a hard compile error.To get rid of the warning, you have to cast:
And an even better compiler will recognize that this cast breaks the
const
promise and instruct the optimizer to not treata
asconst
.As you can see, the quality, capabilities and settings of the compilerwill decide in the end what behavior you can expect. This implies that the same code may show different behavior on different platforms or when using different compilers on the same platform.
If the C standard had defined a behavior for that case, all compilers would have to implement it and no matter what the standard had defined, it would have been hard to implement, putting a huge burden on everyone who wants to write a compiler. Even if the standard had just said "This is forbidden", all compilers would have to perform complex data flow analysis to enforce this rule. So the standard just doesn't define it. It defines that
const
values cannot be changed and if you find a way to change them anyway, there is no behavior you can rely on.是的,您可以更改常量变量的值。
试试这个代码:
Yes, you can change the value of a constant variable.
Try this code: