Pregunta

Estoy jugando con la implementación de NaN etiquetado en un poco de lenguaje de implementación estoy escribiendo en C.Para ello, necesito tomar una doble y meter directamente en su bits.

Lo tengo funcionando ahora mediante la unión de fundición:

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)))

Pero la conversión a un tipo de unión no es estándar ANSI C89.¿Hay una forma segura de hacer esto:

  1. Es -std=c89 -pedantic limpia?
  2. No ir en contra de alias estricto de las reglas?
  3. Puede ser utilizado en el contexto de una expresión como esta:

    Value value = ...
    printf("The number value is %f\n", AS_NUM(value));
    
¿Fue útil?

Solución

Aquí hay una rápida prueba-de-concepto en el que se compila limpio y parece funcionar correctamente para mí.Yo uso memcpy a la finura de tipo de juego de palabras en cuestión.Esto puede, por supuesto, inaceptable en un sistema real, pero al menos portátil.Del mismo modo, no sé si usted tiene la intención de exigir que AS_NUM ser implementado como una macro.

#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));
}

He aquí una transcripción de la compilación (con Clang en OS X) y ejecutar:

$ cc -std=c89 -pedantic blort.c
$ ./a.out
The number value is 1.000000
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top