便携式数据重新解释

Joh*_*nes 14 c type-punning

我想以便携方式(C99)将一种类型的数据重新解释为另一种类型.我不是在谈论铸造,我想重新解释一些给定的数据.此外,通过便携式我的意思是它不会破坏C99规则 - 我并不是说重新解释的值在所有系统上都是相同的.

我知道3种不同的重新解释数据的方法,但其中只有两种是可移植的:

  1. 这不是便携式的 - 它打破了严格的别名规则.

    /* #1 Type Punning */
    
    float float_value = 3.14;
    int *int_pointer = (int *)&float_value;
    int int_value = *int_pointer;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 这是依赖于平台的,因为它int在写入之后从联合中读取值float.但它不会破坏任何C99规则,所以它应该工作(如果sizeof(int) == sizeof(float)).

    /* #2 Union Punning */
    
    union data {
      float float_value;
      int int_value;
    };
    
    union data data_value;
    data_value.float_value = 3.14;
    int int_value = data_value.int_value;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 应该没问题,只要 sizeof(int) == sizeof(float)

    /* #3 Copying */
    
    float float_value = 3.14;
    int int_value = 0;
    memcpy(&int_value, &float_value, sizeof(int_value));
    
    Run Code Online (Sandbox Code Playgroud)

我的问题:

  1. 它是否正确?
  2. 您是否知道以便携方式重新解释数据的其他方法?

Chr*_*oph 18

解决方案2 便携式的 - 通过工会进行类型的惩罚在C99中一直是合法的,并且TC3明确说明了这一点,它在6.5.2.3节中添加了以下脚注:

如果用于访问一个联合对象的内容的部件是不一样的最后用于存储在该对象的值的部件,所述值的对象表示的适当部分被重新解释为在新类型作为对象表示在6.2.6中描述(一个过程有时称为"类型双关语").这可能是陷阱表示.

附件J仍将其列为未指明的行为,这是一个已知的缺陷,并已用C11进行了更正,后者发生了变化

存储在[ 未指定 ]中的最后一个以外的联合成员的值

对应于工会成员的字节值,而不是最后存储到[ 未指定的 ]

这并不是什么大不了的事,因为附件只是提供信息,而不是规范性的.

请记住,您仍然可以最终得到未定义的行为,例如

  • 通过创建陷阱表示
  • 通过在具有指针类型的成员的情况下违反别名规则(由于不需要统一的指针表示,不应该通过类型惩罚转换)
  • 如果联合成员具有不同的大小 - 只有商店上次使用的成员的字节具有指定的值; 特别是,将值存储在较小的成员中也可以使较大成员的尾随字节无效
  • 如果成员包含填充字节,则始终采用未指定的值