当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
我早先使用过工会; 今天,当我读到这篇文章并开始知道这段代码时,我感到震惊
union ARGB
{
uint32_t colour;
struct componentsTag
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} components;
} pixel;
pixel.colour = 0xff040201; // ARGB::colour is the active member from now on
// somewhere down the line, without any edit to pixel
if(pixel.components.a) // accessing the non-active member ARGB::components
Run Code Online (Sandbox Code Playgroud)
实际上是未定义的行为即从工会成员读取而不是最近编写的那个导致未定义的行为.如果这不是工会的预期用途,那是什么?有人可以详细解释一下吗?
更新:
事后我想澄清一些事情.
如果标准布局联合包含多个共享公共初始序列的标准布局结构,并且如果此标准布局联合类型的对象包含其中一个标准布局结构,则允许检查任何标准布局结构的公共初始序列.标准布局结构成员.§9.2/ 19:如果相应的成员具有布局兼容类型且两个成员都不是位字段,或者两者都是具有相同宽度的位字段,则一个或多个初始序列的两个标准布局结构共享一个公共初始序列成员.
C89/90在未指明的行为(附件J)中称之为,而K&R的书称其实施已定义.来自K&R的报价:
这是联合的目的 - 一个可以合法地保存几种类型中的任何一种的变量.[...]只要用法一致:检索到的类型必须是最近存储的类型.程序员有责任跟踪当前存储在联合中的类型; 如果将某些内容存储为一种类型并将其提取为另一种类型,则结果将依赖于实现. …
Stack Overflow问题的一些答案获取浮点数的IEEE单精度位建议使用union类型双关的结构(例如:将a的位float转换为a uint32_t):
union {
float f;
uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;
Run Code Online (Sandbox Code Playgroud)
但是,uint32_t根据C99标准(至少草案n1124),联盟成员的值似乎未指定,其中第6.2.6.1.7节规定:
当值存储在union类型的对象的成员中时,对象表示的字节与该成员不对应但与其他成员对应的字节采用未指定的值.
C11 n1570草案至少有一个脚注似乎暗示不再是这种情况(见6.5.2.3中的脚注95):
如果用于读取union对象的内容的成员与上次用于在对象中存储值的成员不同,则将值的对象表示的适当部分重新解释为新类型中的对象表示形式在6.2.6中描述(一个过程有时被称为''punning'').这可能是陷阱表示.
但是,第C.6.6.1.7节中的案文与C11草案中的C99草案相同.
这种行为在C99下实际上是未指定的吗?它是否在C11中指定?我意识到大多数编译器似乎都支持这一点,但是知道它是在标准中指定还是只是一个非常常见的扩展会很好.
我很确定它只是一些按位操作的问题,我只是不完全确定我应该做什么,并且所有搜索都返回"64位对32位".
如果我有课:
class Odp
{
int i;
int b;
union
{
long f;
struct
{
WCHAR* pwszFoo;
HRESULT hr;
};
};
}
Run Code Online (Sandbox Code Playgroud)
联盟意味着,在列出的所有值中,它一次只能接受其中一个值?在访问这些变量方面,它如何工作?我如何hr直接访问?如果我设置hr,如果我尝试访问会发生什么f?
我们需要支持3个硬件平台--Windows(小端)和Linux嵌入式(大端和小端).我们的数据流依赖于它使用的机器,数据需要分解为位字段.
我想写一个宏(如果可能的话)来抽象出细节.在Linux上,我可以使用bswap_16/ bswap_32/ bswap_64进行Little Endian转换.
但是,我在Visual C++中找不到这个包含.
两个平台(Windows和Linux)都有通用的内置功能吗?
如果没有,那么我可以在Visual C++中使用什么来进行字节交换(除了自己编写 - 希望一些机器优化内置)?
谢谢.
有没有办法在不使用任何外部库(Boost等)的情况下将std :: bitset <64>转换为double?我使用bitset来表示遗传算法中的基因组,我需要一种方法将一组位转换为double.
这是围绕由UB递增NULL指针引起的错误示例的讨论的相关问题
假设我定义了这个数据结构:
union UPtrMem
{
void* p;
char ach[sizeof(void*)];
}
UPtrMem u;
u.p = nullptr;
u.p++; // UB according to standards
u.ach[0]++; // why is this OK then??
Run Code Online (Sandbox Code Playgroud)
p并且ach共享相同的内存,所以仅仅是修改内存位置(恰好包含指针)UB的行为?一旦你试图取消引用指针,我认为它只会被取消定义.
c++ ×6
c ×4
type-punning ×3
unions ×3
c11 ×1
c99 ×1
endianness ×1
linux ×1
pointers ×1
struct ×1
visual-c++ ×1