Vraag Is het veilig om endianess met union te detecteren?


Met andere woorden, volgens de C standaard-, is deze code veilig? (Uitgaan van uint8_t is één byte)

void detectEndianness(void){
    union {
        uint16_t w;
        uint8_t b;
    } a;
    a.w = 0x00FFU;
    if (a.b == 0xFFU) {
        puts("Little endian.");
    }
    else if (a.b == 0U) {
        puts("Big endian.");
    }
    else {
        puts("Stack Overflow endian.");
    }
}

Wat als ik dit in dit verander? Let op de derde if geval dat ik me bewust ben van.

a.w = 1U;
if (a.b == 1U) { puts("Little endian."); }
else if (a.b == 0U) { puts ("Big endian."); }
else if (a.b == 0x80U) { /* Special potential */ }
else { puts("Stack Overflow endian."); }

10
2017-11-22 09:07


oorsprong


antwoorden:


Citaat uit n1570:

6.5.2.3 Structuur en vakbondsleden - p3

Een postfix-uitdrukking gevolgd door de. operator en een identifier   duidt een lid van een structuur- of union-object aan. De waarde is dat   van het genoemde lid, en is een lvalue als de eerste uitdrukking een is   lvalue.

6.2.6 Representaties van typen / 1 Algemeen - p7

Wanneer een waarde wordt opgeslagen in een lid van een object van het type Unie, de   bytes van de objectrepresentatie die daar niet bij horen   lid maar wel overeenkomen met andere leden nemen niet-gespecificeerde waarden.

Het is toegestaan. En uw use-case kan zelfs als een beoogd doel worden beschouwd, als noot 95 wordt in aanmerking genomen (ondanks dat het alleen informatief is):

Als het lid de inhoud van een union-object heeft gelezen, is dit niet de   hetzelfde als het lid dat het laatst werd gebruikt om een ​​waarde in het object op te slaan, de   passend deel van de objectrepresentatie van de waarde is   geherinterpreteerd als een objectrepresentatie in het nieuwe type zoals beschreven   in 6.2.6 (een proces dat ook wel "type punning" wordt genoemd). Dit kan zijn   een traprepresentatie.

Nu, omdat de familie van uintN_t-typen is gedefinieerd om geen opvulbits te hebben

7.20.1.1 Geheel getalgetallen met gehele breedte - p2

De typedefinienaam uintN_t duidt een unsigned integer type aan met   breedte N en geen opvulbits. Dus, uint24_t duidt zo'n niet-ondertekend aan   integer type met een breedte van exact 24 bits.

Al hun bitrepresentaties zijn geldige waarden, geen traprepresentaties zijn mogelijk. Dus moeten we concluderen dat het inderdaad zal controleren op de endianess van uint16_t.


6
2017-11-22 09:16



De standaard (beschikbaar in het gekoppelde online concept) zegt in a voetnoot dat het toegang heeft tot een ander lid van dezelfde vakbond dan het lid dat eerder is geschreven:

95) Als het lid de inhoud van een union-object heeft gelezen, is dat niet het geval   hetzelfde als het lid dat het laatst werd gebruikt om een ​​waarde in het object op te slaan, de   passend deel van de objectrepresentatie van de waarde is   geherinterpreteerd als een objectrepresentatie in het nieuwe type zoals beschreven   in 6.2.6 (een proces dat ook wel '' type punning '' wordt genoemd). Dit kan zijn   een traprepresentatie.

Maar de voetnoot vermeldt ook een mogelijke traprepresentatie en het enige gegevenstype dat door de standaard wordt gegarandeerd als veilig met betrekking tot valstrikkerformaties is unsigned char. Toegang tot traprepresentaties kan een ongedefinieerd gedrag zijn; en hoewel ik dat niet denk unit_32 kan een traprepresentatie op uw platform opleveren, het is in feite afhankelijk van de implementatie of toegang tot dit lid UB is of niet.


1
2017-11-22 09:23



Er is geen vereiste dat de volgorde van bits binnen een byte overeenkomt met de volgorde van de overeenkomstige bits in een groter type. Een conformerende implementatie die definieert uint32_ten heeft een 8-bit unsigned char zou bijvoorbeeld de bovenste 16 bits van de uint32_t op kunnen slaan onder gebruikmaking van vier bits van elke byte, en de onderste 16 bits kunnen opslaan onder gebruikmaking van de overblijvende vier bits van elke byte. Vanuit het oogpunt van de standaard, een van de 32! permutaties van bits zouden even aanvaardbaar zijn.

Dat gezegd hebbende, elke implementatie die niet opzettelijk stompzinnig is en ontworpen is om op een alledaags platform te draaien, gebruikt een van de twee ordeningen [bytes behandelen als groepen van 8 opeenvolgende bits, in de volgorde 0123 of 3210], en een die maakt geen gebruik van een van de bovenstaande en doelen elk platform dat is niet helemaal duister zal gebruiken 2301 of 1032. De standaard verbiedt niet andere orders, maar niet aan te passen zou zeer waarschijnlijk geen problemen veroorzaken, behalve bij het gebruik obtusely -contrived implementaties.


0
2017-12-14 21:01