再次:严格别名规则和char * [英] Once again: strict aliasing rule and char*

查看:134
本文介绍了再次:严格别名规则和char *的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我越读越糊涂,我得到。

从相关的那些最后的问题是最接近我的问题,但我得到了有关对象的生命周期,特别是所有单词混淆 - 它是确定以只读与否


要获得单刀直入。纠正我,如果我错了。

这是好的,海湾合作委员会不​​给予警告,我想读键入 T uint32_t的 )通过的char *

  uint32_t的NUM = 0x01020304;
字符* BUFF = reinter pret_cast<字符*>(试验#);

但是,这是坏(也给出了警告),我其他方式,试图:

 字符的buff [4] = {为0x1,0X2,0x3中,为0x4};
uint32_t的NUM = * reinter pret_cast< uint32_t的*>(BUFF);

如何是第二个从第一个不同的,尤其是当我们谈论重排指令(优化)?另外,加入常量不以任何方式更改的情况。

还是这只是一个单纯的规则,其中明确规定:本可以在一个方向进行,而不是在其他的?
我找不到在标准中任何有关(尤其是在C ++ 11的标准搜索这一点)。

这是C和C ++(因为我读了评论,这意味着它是不同的2种语言)?

相同

我用联盟来解决方法这一点,这似乎仍然是不会 100%确定,因为它不是由标准保证(其中规定,我只能靠价值,这是最后在工会修改)。

所以,在阅读的经过大量的,我现在比较迷茫。我想只有的memcpy 是好的解决方案?


相关问题:


修改结果
在现实世界的情况:我有一个第三方的LIB( http://www.fastcrypto.org/ ),计算UMAC和返回值的的char [4] 。然后,我需要将其转换为 uint32_t的。而且,顺便说一句,在LIB使用的东西像((UINT32 *)PC->随机数)[0] =((UINT32 *)随机数)[0] 很多。不管怎样。

另外,我问什么是对,什么是错的,以及为什么。不仅是重新排序,优化等(有趣的是,与 -O0 没有警告,只能用 -O2 )。

并请注意:我所知道的大/小端的情况。这不是这里的情况。我真的想在这里忽略字节顺序。 严格走样规则,听起来象是很严重的,远比错误的字节顺序更加严重。我的意思是 - 比如访问/修改内存,这是不应该被触及;的任何的那种UB都没有。

从标准(C和C ++)行情将是非常美联社preciated。我找不到关于重叠规则或任何相关的东西。


解决方案

  

是如何从第一个第二个不同,特别是当我们谈论重排指令(优化)?


的问题是在使用规则,以确定这样的优化是否允许编译器。在第二种情况下,你想读通过一个兼容的指针类型,这是不确定的行为的char [] 对象;因此,编译器可能重新排序的读取和写入(或做其他任何事情,你可能不希望)。

由于不自然,因为它看起来,你真的要停止想你是怎么想的编译器可能会优化,以及刚刚的遵守规则


  

还是这只是一个单纯的规则,其中明确规定:本可以在一个方向进行,而不是在其他的?我找不到在标准中任何有关(尤其是在C ++ 11的标准搜索这一点)。


<一个href=\"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf\">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf 3.10章第10节。

在C99,我想也C11,这是6.5第7段。

C和C ++允许通过的char *访问任何对象类型(或具体而言,类型的左值字符 )。他们不允许通过任意类型访问字符对象。所以,是的,规则是单向的规则。


  

我用联盟解决方法这一点,这似乎仍没有100%确定,因为它不是由标准保证(其中规定,我只能靠价值,这是最后一次在工会修改)


虽然标准的写法是可怕的暧昧,在C99(及以后)很明显(至少从C99 TC3)表示的意图的是允许类型通过夯实工会。不过,你必须完成所有访问,通过工会(特别是你不能只是'投了工会为存在的类型双关语的目的)。


  

返回的值是CHAR [4]。然后,我需要将其转换为uint32_t的


只要使用的memcpy 或手动字节移到正确的位置,以防字节排序是一个问题。良好的编译器能够优化反正这一点(是的,甚至调用的memcpy )。

The more I read, the more confused I get.

The last question from the related ones is closest to my question, but I got confused with all words about object lifetime and especially - is it OK to only read or not.


To get straight to the point. Correct me if I'm wrong.

This is fine, gcc does not give warning and I'm trying to "read type T (uint32_t) via char*":

uint32_t num = 0x01020304;
char* buff = reinterpret_cast< char* >( &num );

But this is "bad" (also gives a warning) and I'm trying "the other way around":

char buff[ 4 ] = { 0x1, 0x2, 0x3, 0x4 };
uint32_t num = *reinterpret_cast< uint32_t* >( buff );

How is the second one different from the first one, especially when we're talking about reordering instructions (for optimization)? Plus, adding const does not change the situation in any way.

Or this is just a straight rule, which clearly states: "this can be done in the one direction, but not in the other"? I couldn't find anything relevant in the standards (searched for this especially in C++11 standard).

Is this the same for C and C++ (as I read a comment, implying it's different for the 2 languages)?


I used union to "workaround" this, which still appears to be NOT 100% OK, as it's not guaranteed by the standard (which states, that I can only rely on the value, which is last modified in the union).

So, after reading a lot, I'm now more confused. I guess only memcpy is the "good" solution?


Related questions:


EDIT
The real world situation: I have a third party lib (http://www.fastcrypto.org/), which calculates UMAC and the returned value is in char[ 4 ]. Then I need to convert this to uint32_t. And, btw, the lib uses things like ((UINT32 *)pc->nonce)[0] = ((UINT32 *)nonce)[0] a lot. Anyway.

Also, I'm asking about what is right and what is wrong and why. Not only about the reordering, optimization, etc. (what's interesting is that with -O0 there are no warnings, only with -O2).

And please note: I'm aware of the big/little endian situation. It's not the case here. I really want to ignore the endianness here. The "strict aliasing rules" sounds like something really serious, far more serious than wrong endianness. I mean - like accessing/modifying memory, which is not supposed to be touched; any kind of UB at all.

Quotes from the standards (C and C++) would be really appreciated. I couldn't find anything about aliasing rules or anything relevant.

解决方案

How is the second one different from the first one, especially when we're talking about reordering instructions (for optimization)?

The problem is in the compiler using the rules to determine whether such an optimization is allowed. In the second case you're trying to read a char[] object via an incompatible pointer type, which is undefined behavior; hence, the compiler might re-order the read and write (or do anything else which you might not expect).

As unnatural as it might seem, you really have to stop thinking about how you think the compiler might optimize, and just obey the rules.

Or this is just a straight rule, which clearly states: "this can be done in the one direction, but not in the other"? I couldn't find anything relevant in the standards (searched for this especially in C++11 standard).

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf chapter 3.10 paragraph 10.

In C99, and I think also C11, it's 6.5 paragraph 7.

Both C and C++ allow accessing any object type via char * (or specifically, an lvalue of type char). They do not allow accessing a char object via an arbitrary type. So yes, the rule is a "one way" rule.

I used union to "workaround" this, which still appears to be NOT 100% OK, as it's not guaranteed by the standard (which states, that I can only rely on the value, which is last modified in the union).

Although the wording of the standard is horribly ambiguous, in C99 (and beyond) it's clear (at least since C99 TC3) that the intent is to allow type-punning through a union. You must however perform all accesses through the union (in particular you cannot just 'cast a union into existence' for purpose of type-punning).

the returned value is in char[ 4 ]. Then I need to convert this to uint32_t

Just use memcpy or manually shift the bytes to the correct position, in case byte-ordering is an issue. Good compilers can optimize this out anyway (yes, even the call to memcpy).

这篇关于再次:严格别名规则和char *的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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