类型转换后,错误值做作 [英] Bad value affectation after type casting

查看:205
本文介绍了类型转换后,错误值做作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是固有无符号长变量作为缓冲来存放它里面两个无符号短的变量。从我的C ++知识,它应该是一个有效的方法。我用这个方法来存储内的一个无符号短很多次2 unsigned char型没有任何问题。不幸的是在使用不同的体系结构时,它奇怪的反应。它似乎更新第二分配后的值。在(溢流)的情况是根本没有进行论证。任何人都可以解释为什么它会那样一些轻?

 无符号长dwTest = 0xFFEEDDCC;的printf(的sizeof(无符号短)=%d个\\ N的sizeof(无符号短));
的printf(dwTest =%08X \\ n,dwTest);//地址+值
的printf(地址+值:%08X< - %08X,%08X< - %08X \\ n,(DWORD)(及((无符号短*)及dwTest)[0]),(((无符号短*)及dwTest)[0]),(DWORD)(及((无符号短*)及dwTest)[1]),(((无符号短*)及dwTest)[1])) ;((无符号短*)及dwTest)[0] =(WORD)加上0xAAAA;
的printf(dwTest =%08X \\ n,dwTest);((无符号短*)及dwTest)[1] =(WORD)0xBBBB;
的printf(dwTest =%08X \\ n,dwTest);//(溢出)
((无符号短*)及dwTest)[2] =(WORD)0X9999;的printf(dwTest =%08X \\ n,dwTest);

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

 的sizeof(无符号短)= 2
dwTest = FFEEDDCC
地址+值:0031F728< - 0000DDCC,0031F72A< - 0000FFEEdwTest = FFEEAAAAdwTest = BBBBAAAAdwTest = BBBBAAAA

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

 的sizeof(无符号短)= 2
dwTest = FFEEDDCC
地址+值:7FAFECD8< - 0000DDCC,7FAFECDA< - 0000FFEEdwTest = FFEEDDCCdwTest = FFEEAAAAdwTest = BBBBAAAA


解决方案

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

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

所以,引入了严格走样规则。它基本上说,两个指针只能互为别名时,他们是同一类型的。作为一个特殊的规则,的char * 可引用任何其他指针(而不是周围的其他方法)。 这打破了通过指针型双关,并让编译器生成更有效的code。当GCC检测型双关,并启用了警告,它会这样提醒你:

 警告:提领型punned指针将打破严格走样规则

另一种方式做类型双关是通过工会:

 工会{
    INT I;
    短S [2];
} U;
u.i = 0xDEADBEEF;
U.S [0] = 0xBABE;
....

这开辟了蠕虫的一个新的整体能。在最好的情况下,这是实现有关。现在,我没有进入C89标准,但在C99它最初表示,比存入最后一个以外的工会成员的值是不确定的。这是在一个TC变为指出的字节不对应于值最后存储-成构件是未指定的,并以其他方式指出,该执行字节对应PTED最后存进构件是reinter $ P $根据新的类型(东西这显然是依赖于实现的)。

对于C ++,我找不到有关标准联盟破解的语言。不管怎么说,C ++有 reinter pret_cast<> ,这是你应该用C使用什么类型双关++(使用的参考变量reinter pret_cast<方式>

不管怎么说,你可能不应该使用类型双关(实现相关的),你应该通过位移手动建立自己的价值。

I am using a native unsigned long variable as a buffer used to contain two unsigned short variable inside it. From my knowledge of C++ it should be a valid method. I used this method to store 2 unsigned char inside one unsigned short many times without any problem. Unfortunately when using it on a different architecture, it react strangely. It seems to update the value after a second assignation. The (Overflow) case is there simply to demonstrate it. Can anyone shed some light on why it react that way?

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 output (OK):

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

dwTest = FFEEAAAA

dwTest = BBBBAAAA

dwTest = BBBBAAAA

ARM9 GCC Crosstool output (Doesn't work):

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

dwTest = FFEEDDCC

dwTest = FFEEAAAA

dwTest = BBBBAAAA

解决方案

What you are trying to do is called type-punning. There are two traditional ways to do it.

A way to do it is via pointers (what you have done). Unfortunately, this conflicts with the optimizer. You see, due to the halting problem, the optimizer cannot know in the general case that two pointers don't alias each other. This means that the compiler has to reload any value that may have been modified via a pointer, resulting in tons of potentially unnecessary reloads.

So, the strict-aliasing rule was introduced. It basically says that two pointers can only alias each other when they are of the same type. As a special rule, a char * can alias any other pointer (but not the other way around). This breaks type-punning via pointers, and lets the compiler generate more efficient code. When gcc detects type-punning and has warnings enabled, it will warn you thus:

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

Another way to do type-punning is via the union:

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

This opens up a new whole can of worms. In the best case, this is implementation dependant. Now, I don't have access to the C89 standard, but in C99 it originally stated that the value of an union member other than the last one stored into is unspecified. This was changed in a TC to state that the values of bytes that don't correspond to the last stored-into member are unspecified, and stated otherwise that the bytes that do correspond to the last stored-into member are reinterpreted as per the new type (something which is obviously implementation dependant).

For C++, I can't find the language about the union hack in the standard. Anyways, C++ has reinterpret_cast<>, which is what you should use for type-punning in C++ (use the reference variant of reinterpret_cast<>).

Anyways, you probably shouldn't be using type-punning (implementation-dependant), and you should build up your values manually via bit-shifting.

这篇关于类型转换后,错误值做作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆