首页 > 解决方案 > 严格别名警告:将 uint64_t 变量类型转换为 64 位大小的结构

问题描述

我正在努力解决 Linux (4.19.21-linux-gnu-gcc) 上的 C 程序中的以下问题,

//Structure definition :

struct data_from_u64 {
uint32_t u32_value;
uint16_t u16_value;
uint8_t u8_value1;
uint8_t u8_value2;
}

//Expectation : Convert a incoming uint64_t variable to the above structure using the below macro, 

#define U64_TO_STRUCT(u64_value)  ( * (data_from_u64 *) ((void*)  &(u64_value)) )

//Usage
  data_from_u64 data = U64_TO_STRUCT(u64_value);

项目很大,应用非常广泛,但新的编译程序在编译时强制执行“-O2”和“-Werror”标志。您能否帮助解决下面提到的错误/警告。更改应该是最小的,因为这个宏在 1000 多个地方使用。

错误/警告:

错误:取消引用类型双关指针将破坏严格别名规则 [-Werror=strict-aliasing] #define U64_TO_STRUCT(u64_value) ( * (data_from_u64 ) ((void ) &(u64_value)) )

我尝试了什么:

我试过做memcpy,它有效。但它需要在所有 1000 个使用位置进行更新[它需要更改宏的参数以包含目标]。

标签: cgccstrict-aliasing

解决方案


你可以使用这个:

struct data_from_u64 U64_TO_STRUCT(uin64_t u64_value) {
    struct data_from_u64 ret;
    memcpy(&ret, &u64_value, sizeof u64_value);
    return ret;
}

不能返回这样的结构是一个常见的误解。您不能返回本地数组,但返回结构非常好。

从中吸取的教训是,我们在 SO 的所有关于“你违反了抗锯齿规则”的唠叨不仅仅是一些在实践中无关紧要的书呆子胡说八道。正如您自己所看到的,它确实会产生现实世界的后果。:)

如果您真的想为此使用宏,请查看Eric 的答案,该答案效果很好,符合标准并且不依赖于编译器扩展。我个人只是不喜欢宏之类的功能。


推荐阅读