类型转换后的错误值影响

时间:2011-11-15 22:09:21

标签: casting arm unsigned

我使用本机无符号长变量作为缓冲区,用于在其中包含两个无符号短变量。根据我对C ++的了解,它应该是一种有效的方法。我使用这种方法在一个unsigned short中多次存储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

1 个答案:

答案 0 :(得分:2)

你要做的是称为打字。有两种传统的方法可以做到。

一种方法是通过指针(你做了什么)。不幸的是,这与优化器冲突。你会看到,由于暂停问题,优化器在一般情况下无法知道两个指针之间没有别名。这意味着编译器必须重新加载可能通过指针修改的任何值,从而导致大量可能不必要的重新加载。

因此,引入了严格别名规则。它基本上表示当两个指针属于同一类型时,它们只能互为别名。作为一项特殊规则,char *可以为任何其他指针设置别名(但不是相反)。 这会通过指针打破类型惩罚,并让编译器生成更高效的代码。当gcc检测到类型惩罚并启用了警告时,它会发出警告:

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

另一种做类型惩罚的方法是通过union:

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

这开辟了一整套新蠕虫。在最好的情况下,这取决于实现。现在,我无法访问C89标准,但在C99中,它最初声明未指定存储的最后一个工会成员的值。在TC中对此进行了更改,以指出与上一个存储成员不对应的字节值未指定,并且另外说明与最后一个存储成员对应的字节按照新的成员重新解释类型(显然依赖于实现的东西)。

对于C ++,我在标准中找不到关于联合黑客的语言。无论如何,C ++有reinterpret_cast<>,这是你应该用于C ++中的类型惩罚(使用reinterpret_cast<>的引用变体)。

无论如何,你可能不应该使用类型惩罚(依赖于实现),你应该通过位移来手动建立你的值。