Kann memcpy für Typ-Punning verwendet werden?

Dies ist ein Zitat aus dem C11-Standard:

6.5 Ausdrücke
...

6 Daseffektiver Typ eines Objekts für einen Zugriff auf seinen gespeicherten Wert ist der deklarierte Typ des Objekts, falls vorhanden. Wenn ein Wert in einem Objekt ohne deklarierten Typ über einen Wert mit einem Typ gespeichert wird, der kein Zeichentyp ist, wird der Typ des Werts zum effektiven Typ des Objekts für diesen Zugriff und für nachfolgende Zugriffe, die den nicht ändern gespeicherter Wert. Wenn ein Wert mit @ in ein Objekt ohne deklarierten Typ kopiert wimemcpy odermemmove oder wird als Array des Zeichentyps kopiert, dann ist der effektive Typ des geänderten Objekts für diesen Zugriff und für nachfolgende Zugriffe, die den Wert nicht ändern, der effektive Typ des Objekts, von dem der Wert kopiert wird, falls vorhanden einer. Bei allen anderen Zugriffen auf ein Objekt ohne deklarierten Typ ist der effektive Typ des Objekts einfach der Typ des für den Zugriff verwendeten Werts.

7 Auf den gespeicherten Wert eines Objekts darf nur mit einem Werteausdruck eines der folgenden Typen zugegriffen werden:

- ein Typ, der mit dem effektiven Typ des Objekts kompatibel ist,
- eine qualifizierte Version eines Typs, der mit dem effektiven Typ des Objekts kompatibel ist,
- Ein Typ, der der vorzeichenbehaftete oder vorzeichenlose Typ ist, der dem effektiven Typ des Objekts entspricht.
- Ein Typ, der der vorzeichenbehaftete oder vorzeichenlose Typ ist, der einer qualifizierten Version des effektiven Typs des Objekts entspricht.
- ein Aggregat- oder Vereinigungstyp, der einen der oben genannten Typen unter seinen Mitgliedern enthält (einschließlich rekursiv eines Mitglieds eines Unteraggregats oder einer enthaltenen Vereinigung), oder
- ein Zeichentyp.

Bedeutet dies, dassmemcpy kann nicht für das Punning von Typen verwendet werden:

double d = 1234.5678;
uint64_t bits;
memcpy(&bits, &d, sizeof bits);
printf("the representation of %g is %08"PRIX64"\n", d, bits);

Warum würde es nicht die gleiche Ausgabe geben wie:

union { double d; uint64_t i; } u;
u.d = 1234.5678;
printf("the representation of %g is %08"PRIX64"\n", d, u.i);

Was passiert, wenn ich meine Version von @ verwendmemcpy mit Zeichentypen:

void *my_memcpy(void *dst, const void *src, size_t n) {
    unsigned char *d = dst;
    const unsigned char *s = src;
    for (size_t i = 0; i < n; i++) { d[i] = s[i]; }
    return dst;
}

BEARBEITEN EOF hat kommentiert, dassDer Teil übermemcpy() in Absatz 6 gilt in dieser Situation nicht, dauint64_t bits hat einen deklarierten Typ. Ich stimme zu, aber leider hilft dies nicht bei der Beantwortung der Frage, obmemcpy kann für das Punning von Typen verwendet werden, macht jedoch Absatz 6 für die Beurteilung der Gültigkeit der obigen Beispiele irrelevant.

Hier ist ein weiterer Versuch, mit @ zu tippmemcpy dass ich glaube, würde durch Absatz 6 abgedeckt werden:

double d = 1234.5678;
void *p = malloc(sizeof(double));
if (p != NULL) {
    uint64_t *pbits = memcpy(p, &d, sizeof(double));
    uint64_t bits = *pbits;
    printf("the representation of %g is %08"PRIX64"\n", d, bits);
}

Assumingsizeof(double) == sizeof(uint64_t), Hat der obige Code ein definiertes Verhalten gemäß den Absätzen 6 und 7?

BEARBEITEN Einige Antworten verweisen auf die Möglichkeit eines undefinierten Verhaltens, das beim Lesen einer Trap-Darstellung auftritt. Dies ist nicht relevant, da der C-Standard diese Möglichkeit ausdrücklich ausschließt:

7.20.1.1 Integer-Typen mit exakter Breite

1 Der eingegebene NameintN_t bezeichnet einen vorzeichenbehafteten Integer-Typ mit der BreiteN, keine Füllbits und eine Zweierkomplementdarstellung. Also,int8_t bezeichnet einen solchen vorzeichenbehafteten Integer-Typ mit einer Breite von genau 8 Bit.

2 Der eingegebene NameuintN_t bezeichnet einen vorzeichenlosen Integer-Typ mit der BreiteN und keine Füllbits. Also,uint24_t bezeichnet einen solchen vorzeichenlosen Integer-Typ mit einer Breite von genau 24 Bit.

Diese Typen sind optional. Wenn eine Implementierung jedoch Integer-Typen mit einer Breite von 8, 16, 32 oder 64 Bit, keine Füllbits und (für die vorzeichenbehafteten Typen) eine Zweierkomplementdarstellung bereitstellt, definiert sie die entsprechenden Typdefinitionsnamen.

Artuint64_t hat genau 64 Wertebits und keine Füllbits, daher kann es keine Trap-Darstellungen geben.

Antworten auf die Frage(10)

Ihre Antwort auf die Frage