2011-11-15 42 views
0

我正在使用一个本地无符号长变量作为缓冲区,用于在其中包含两个无符号短变量。从我对C++的知识来看,它应该是一个有效的方法。我用这种方法在一次无符号短内部多次存储2个unsigned char,没有任何问题。不幸的是,当在不同的架构上使用它时,它的反应很奇怪。它似乎在第二次分配后更新该值。 (溢出)案例就是为了演示它。任何人都可以阐明为什么它会这样反应吗?类型转换后的值不正确

unsigned long dwTest = 0xFFEEDDCC; 

printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short)); 
printf("dwTest = %08X\n", dwTest); 

//Address + values 
printf("Addresses + Values: %08X <- %08X, %08X <- %08X\n", (DWORD)(&((unsigned short*)&dwTest)[0]), (((unsigned short*)&dwTest)[0]), (DWORD)(&((unsigned short*)&dwTest)[1]), (((unsigned short*)&dwTest)[1])); 

((unsigned short*)&dwTest)[0] = (WORD)0xAAAA; 
printf("dwTest = %08X\n", dwTest); 

((unsigned short*)&dwTest)[1] = (WORD)0xBBBB; 
printf("dwTest = %08X\n", dwTest); 

//(Overflow) 
((unsigned short*)&dwTest)[2] = (WORD)0x9999; 

printf("dwTest = %08X\n", dwTest); 

的Visual C++ 2010的输出(OK):

sizeof(unsigned short) = 2 
dwTest = FFEEDDCC 
Addresses + Values: 0031F728 <- 0000DDCC, 0031F72A <- 0000FFEE 

dwTest = FFEEAAAA 

dwTest = BBBBAAAA 

dwTest = BBBBAAAA 

ARM9 GCC crosstool的输出(不工作):

sizeof(unsigned short) = 2 
dwTest = FFEEDDCC 
Addresses + Values: 7FAFECD8 <- 0000DDCC, 7FAFECDA <- 0000FFEE 

dwTest = FFEEDDCC 

dwTest = FFEEAAAA 

dwTest = BBBBAAAA 
+0

编译启用警告('-Wall')并查看警告。然后在这里环顾这个“严格别名”(解决方案:使用联盟)。 – ninjalj

回答

2

你所试图做的是叫类型 - 双关语。有两种传统的方式来做到这一点。

一种方法是通过指针(你所做的)。不幸的是,这与优化器冲突。你看,由于暂停问题,优化器在一般情况下无法知道两个指针不会互相混叠。这意味着编译器必须重新加载可能已经通过指针修改的任何值,导致大量潜在的不必要的重新加载。

因此引入了严格别名法则。它基本上说,两个指针只能在相同类型时相互混淆。作为一个特殊规则,char *可以别名任何其他指针(但不能以其他方式)。 这打破了通过指针的类型双击,并让编译器生成更高效的代码。当GCC检测型双关,并已打开了警告,它会警告你这样的:

warning: dereferencing type-punned pointer will break strict-aliasing rules 

另一个办法型双关是通过工会:

union { 
    int i; 
    short s[2]; 
} u; 
u.i = 0xDEADBEEF; 
u.s[0] = 0xBABE; 
.... 

这开辟了一个新的整体可的蠕虫。在最好的情况下,这是依赖于实现的。现在,我没有权限访问C89标准,但是在C99中,它最初声明除了最后一个存储的联合成员的值是未指定的。这在TC中被改变以表明不与最后一个存储成员相对应的字节值是未指定的,并且另外声明,与最后存储的成员相对应的字节被重新解释为根据新的类型(明显依赖于实现的东西)。

对于C++,我无法在标准中找到有关联合黑客的语言。无论如何,C++有reinterpret_cast<>,这就是你应该用C++中的type-punning(使用参考变量reinterpret_cast<>)。

无论如何,你可能不应该使用type-punning(依赖于实现),并且你应该通过位移来手动建立你的值。

+0

感谢您的完整澄清的答案 – Dunge