如何在标准C89中使用双精度浮点数的位级表示?

4
我正在考虑在我用C语言编写的小型语言实现中实现NaN标记。为此,我需要直接访问一个双精度浮点数的位。
我已经使用联合转换使其工作:
typedef union
{
  double num;
  unsigned long bits;
} Value;

/* A mask that selects the sign bit. */
#define SIGN_BIT (1UL << 63)

/* The bits that must be set to indicate a quiet NaN. */
#define QNAN (0x7ff8000000000000L)

/* If the NaN bits are set, it's not a number. */
#define IS_NUM(value) (((value).bits & QNAN) != QNAN)

/* Convert a raw number to a Value. */
#define NUM_VAL(n) ((Value)(double)(n))

/* Convert a Value representing a number to a raw double. */
#define AS_NUM(value) (value.num)

/* Converts a pointer to an Obj to a Value. */
#define OBJ_VAL(obj) ((Value)(SIGN_BIT | QNAN | (unsigned long)(obj)))

/* Converts a Value representing an Obj pointer to a raw Obj*. */
#define AS_OBJ(value) ((Obj*)((value).bits & ~(SIGN_BIT | QNAN)))

但是将类型转换为联合类型不符合标准的 ANSI C89。有可靠的方法可以实现这一点吗?
  1. Is -std=c89 -pedantic clean?
  2. Doesn't run afoul of strict aliasing rules?
  3. Can be used in an expression context like this:

    Value value = ...
    printf("The number value is %f\n", AS_NUM(value));
    

2
在许多系统上,unsigned long 是32位的。你应该使用 stdint.h 中的 uint64_t:不幸的是,那是一个C99头文件。 - gsg
为什么要使用1989年的C语言?现今大多数编译器都支持至少C 1999,并且C 1999(tC3)支持通过联合体进行别名处理。除非有强制性的原因,否则新软件不应该使用旧的、被替代的语言 - Eric Postpischil
1个回答

3
这是一个快速的概念验证,编译干净且运行正常。我使用memcpy来解决类型转换问题。在真实系统中,这种方法可能不可接受,但至少是可移植的。同样地,我不知道你是否打算要求AS_NUM作为宏来实现。
#include <stdio.h>
#include <string.h>

typedef struct {
    char raw[sizeof(double)];
} Value;

static Value valueFromDouble(double d) {
    Value result;
    memcpy(result.raw, &d, sizeof(result));
    return result;
}

static double AS_NUM(Value value) {
    double result;
    memcpy(&result, value.raw, sizeof(result));
    return result;
}

int main(int argc, char **argv) {
    Value value = valueFromDouble(1.0);
    printf("The number value is %f\n", AS_NUM(value));
}

以下是它(在OS X上使用Clang)的编译和运行过程的转录:
$ cc -std=c89 -pedantic blort.c
$ ./a.out
The number value is 1.000000

1
非常好。调用函数,然后调用memcpy并返回结果的副本似乎有点多余,只是为了在原地重新解释完全相同的位,但是查看汇编输出,似乎编译器将其全部优化掉了。谢谢! - munificent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接