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中指定?我意识到大多数编译器似乎都支持这一点,但是知道它是在标准中指定还是只是一个非常常见的扩展会很好.
我正在开发一个项目来构建一个小编译器,只是为了它.
我决定采用构建一个非常简单的虚拟机来实现目标,所以我不必担心学习精灵,英特尔组装等的来龙去脉.
我的问题是关于使用工会在C中打字.我决定只在vm的内存中支持32位整数和32位浮点值.为方便起见,vm的"主内存"设置如下:
typedef union
{
int i;
float f;
}word;
memory = (word *)malloc(mem_size * sizeof(word));
Run Code Online (Sandbox Code Playgroud)
所以我可以根据指令将内存部分视为int或float.
这在技术上是打字吗?当然,如果我使用int作为内存的话,然后使用float*来像浮点数一样对待它们.我目前的方法虽然在语法上有所不同,但我认为它在语义上并不相同.最后,我仍然将内存中的32位视为int或float.
我在网上提出的唯一信息表明这是依赖于实现的.是否有更便携的方式来实现这一点而不浪费一大堆空间?
我可以做到以下几点,但接下来我会占用相当于工会的2倍以上的记忆和"重新发明轮子".
typedef struct
{
int i;
float f;
char is_int;
}
Run Code Online (Sandbox Code Playgroud)
编辑
我也许没有说清楚我的确切问题.我知道我可以使用一个没有未定义行为的联合中的float或int.我所追求的是一种具有32位内存位置的方法,我可以安全地将其用作int或float,而不知道最后一个值集是什么.我想说明使用其他类型的情况.
char a[] = "abc"; // movl $6513249, -12(%rbp)
char ab[] = "ab"; // movw $25185, -11(%rbp)
char abc[] = "a"; // movw $97, -10(%rbp)
Run Code Online (Sandbox Code Playgroud)
上面的 C 代码在汇编 (gcc -S code.c) 中表示为:
movl $6513249, -12(%rbp)
movw $25185, -15(%rbp)
movw $97, -17(%rbp)
Run Code Online (Sandbox Code Playgroud)
97 是十进制的“a”,但为什么“ab”是 25185 而“abc”是 6513249?