Bästa svaret
Ett väldigt taggigt sammanfall när man måste matcha strukturförskjutningar över maskingränser eller nätverksprotokoll . Specifikationen säger att storleken måste vara det minsta som krävs för att representera det största värdet det kan ta. Så en typisk tillståndsmaskintillstånd kan till exempel bara kräva en byte.
Det finns bara tre sätt att styra storleken på AFAIK:
några (men inte alla) kompilatorer har en kompilatoromkopplare för att tvinga storleken till antingen sizeof (int) eller till 32 bitar. Växelsyntaxen är inte densamma mellan säg MSC och gccc / clang.
Det andra sättet, om du behöver fylla säg ett 16-bitarsfält, är att definiera ett dummy maxvärde som kräver den storleken.
Det andra sättet är att använda vanliga int-stilar i strukturdefinitionerna, men då går man ifrån felsökningsanvändningen att det visar värdet med enumnamn och bara får heltal istället.
Då kommer man förmodligen behöva ange strukturen som innehåller enum är packad, inte vadderad.
Svar
Om ingen del av någon variabel x
är const
eller volatile
, och x
är inte av arraytyp, då gör uttalandet …
x = x;
… ganska mycket ingenting. Det är välformerat. Förutsatt att x
initialiserades i förväg, ¹ det är också väldefinierat. Uppdraget gör inte ändrar inte programmets tillstånd med några undantag (se nedan).
Detta gäller även om x
har en struct
typ.
struct foo {
char buf[42];
int x;
};
struct foo x = { "Hello World", 18 };
x = x; // no big deal.
Så vad är ”misstaget”? Det är inte användbar kod, men det finns en hel del kod som passar den beskrivningen. Det är bara ett misstag om du siktade på att göra något annat och missade.
[Tillägg: Med tanke på detta uppdrag ”är värdelöshet, sammanställare benägna att varna för det, eftersom det är ganska troligt att du gjorde betyder något annat.]
Varför lite om const
och iv id = ”3bb41f7bd8” Begränsningen för const
är enkel: det betyder ”skrivskyddad”, så du kan inte skriva till den. Åtminstone inte med enkel uppgift.
Den som gäller volatile
är svårare. Det nyckelordet säger att det värde som kvalificeras av det kan ändras på sätt som inte är synliga för implementeringen, och som skriver till det kan ha biverkningar. Utan att gräva i ett rathål här, i praktiken ser de enda rimligt väldefinierade operationerna du kan utföra på ett flyktigt objekt ut så här:
volatile int v;
int i;
i = v; // reads from v once, places into i.
v = i; // writes to v once with the contents of i.
Du kan göra lite mer än så med sanning med volatile
, men bara något. Det är ett ämne för en annan dag. Det är en anledning till att C ++ 20 avskaffade volatile
utom några få användningar. Deras förändringar ser ganska förnuftiga ut.
Jag nämnde några möjliga undantag ovan. Jonas Oberhauser påminde mig om att varje stoppning i en struct
inte nödvändigtvis bevaras av den uppgiften.
Det är också teoretiskt möjligt att underliggande representation för objekt kan ändras på grund av tilldelningen, om samma värde kan representeras på flera sätt.
Förhoppningsvis är ditt program okänsligt för båda möjligheterna. Om du någonsin tittar på den underliggande -representationen av objektet kan du dock se skillnader. Funktioner som memcmp
kanske till exempel märker. På samma sätt om du använder typ punning.
¹ Och om det inte var välkommen till odefinierat beteende, eftersom du förmodligen går illa med en av dessa:
- Värdet på ett objekt med automatisk lagringstid används medan det är obestämt ( 6.2 .4 , 6.7.9 , 6.8 ).
- Ett värde som anger ett objekt med automatisk lagringstid som kunde ha deklarerats med registerlagringsklassen används i ett sammanhang som kräver värdet på det angivna objektet, men objektet är oinitialiserat. ( 6.3.2.1 ).