这不是学术代码或假设的问题。最初的问题是将代码从HP11转换为HP1123 Itanium。基本上它归结为HP1123 Itanium上的编译错误。在Windows上进行复制时,我真的很抓头。除了最基本的方面之外我已经删除了......如果按原样运行它,你可能必须按下控制器D退出控制台窗口:
#include "stdafx.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
char blah[6];
const int IAMCONST = 3;
int *pTOCONST;
pTOCONST = (int *) &IAMCONST;
(*pTOCONST) = 7;
printf("IAMCONST %d \n",IAMCONST);
printf("WHATISPOINTEDAT %d \n",(*pTOCONST));
printf("Address of IAMCONST %x pTOCONST %x\n",&IAMCONST, (pTOCONST));
cin >> blah;
return 0;
}
这是输出
IAMCONST 3
WHATISPOINTEDAT 7
Address of IAMCONST 35f9f0 pTOCONST 35f9f0
我只能说是什么?这样做是不明确的?对于这样一个简单的例子,这是我看到的最违反直觉的事情。
更新
确实在搜索了一下菜单调试&gt;&gt; Windows&gt;&gt;反汇编具有下面描述的优化。
printf("IAMCONST %d \n",IAMCONST);
0024360E mov esi,esp
00243610 push 3
00243612 push offset string "IAMCONST %d \n" (2458D0h)
00243617 call dword ptr [__imp__printf (248338h)]
0024361D add esp,8
00243620 cmp esi,esp
00243622 call @ILT+325(__RTC_CheckEsp) (24114Ah)
谢谢大家!
答案 0 :(得分:24)
看起来编译器正在优化
printf("IAMCONST %d \n",IAMCONST);
到
printf("IAMCONST %d \n",3);
因为您说 IAMCONST
是const int
。
但是因为你正在使用IAMCONST
的地址,所以它必须实际位于堆栈的某个地方,并且const
不能强制执行,因此该位置的内存(毕竟*pTOCONST
)是可变的。
简而言之:你遗弃了const
,不要这样做。可怜,手无寸铁的C ......
使用GCC for x86,-O0
(无优化),生成的程序集
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $36, %esp
movl $3, -12(%ebp)
leal -12(%ebp), %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl $7, (%eax)
movl -12(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
movl -8(%ebp), %eax
movl (%eax), %eax
movl %eax, 4(%esp)
movl $.LC1, (%esp)
call printf
从堆栈上的*(bp-12)
复制到printf
的参数。但是,使用-O1
(以及-Os
,-O2
,-O3
和其他优化级别),
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
movl $3, 4(%esp)
movl $.LC0, (%esp)
call printf
movl $7, 4(%esp)
movl $.LC1, (%esp)
call printf
您可以清楚地看到使用常量3
。
如果您使用的是Visual Studio的CL.EXE
,则/Od
会禁用优化。这因编译器而异。
警告C编译器allows C编译器假设任何int *
指针的目标永远不会重叠const int
的内存位置,所以你真的不应该如果你想要可预测的行为,那么就这样做。
答案 1 :(得分:6)
常量值IAMCONST被内联到printf调用中。
你所做的事情充其量是错误的,并且很可能是C ++标准未定义的。我的猜测是C ++标准让编译器可以自由地内联一个const原语,它是函数声明的本地原语。原因是价值不应该改变。
然后,它是C ++应该和可以是非常不同的单词。
答案 2 :(得分:4)
你很幸运,编译器正在进行优化。另一种处理方法是将const整数放入只读内存中,然后尝试修改该值会导致核心转储。
答案 3 :(得分:2)
通过删除const的转换来写入const对象是未定义的行为 - 所以在你这样做的时候:
(*pTOCONST) = 7;
所有赌注都已关闭。
来自C ++标准7.1.5.1(cv-qualifiers):
除了可以修改声明为mutable(7.1.1)的任何类成员之外,任何修改const的尝试都是如此 对象在其生命周期(3.8)中导致未定义的行为。
因此,编译器可以自由地假设IAMCONST
的值不会改变,因此它可以优化对实际存储的访问。实际上,如果从不采用const对象的地址,编译器可能会完全取消对象的存储。
另请注意(再次在7.1.5.1中):
由积分常量表达式初始化的非易失性const限定的整数或枚举类型的变量可用于积分常量表达式(5.19)。
这意味着IAMCONST可用于编译时常量表达式(即,为枚举或数组大小提供值)。在运行时改变它甚至意味着什么?
答案 4 :(得分:-3)
编译器是否优化无关紧要。你问了麻烦,你很幸运,你自己遇到了麻烦,而不是等待客户报告给你。
“我只能说是什么?这样做是不确定的?对于这样一个简单的例子,这是我见过的最违反直觉的事情。”
如果您真的相信那么您需要切换到您可以理解或改变职业的语言。为了您自己和您的客户,请停止使用C或C ++或C#。
const int IAMCONST = 3;
你说的。
int *pTOCONST;
pTOCONST = (int *) &IAMCONST;
猜猜为什么编译器抱怨你是否省略了你的邪恶演员。在你撒谎之前,编译器可能已经说出了真相。
“邪恶的演员会被邪恶的编辑器打败吗?”
没有。邪恶的演员自己被打败了。无论你的编译器是否试图告诉你真相,编译器都不是邪恶的。