Beste antwoord
Een zeer netelig raadsel, wanneer men structuuroffsets moet matchen over machinegrenzen of netwerkprotocollen heen . De specificatie zegt dat de grootte het minimum moet zijn dat nodig is om de grootste waarde te vertegenwoordigen die het kan hebben. Dus een typische toestandsopsomming van een toestandsmachine vereist misschien alleen een byte.
Er zijn AFAIK slechts drie manieren om de grootte te controleren:
sommige (maar niet alle) compilers hebben een compilerschakelaar om de grootte te forceren naar sizeof (int) of naar 32 bits. De schakelsyntaxis is niet hetzelfde tussen bijvoorbeeld MSC en gccc / clang.
De tweede manier, als je bijvoorbeeld een 16-bits veld moet invullen, is om een dummy max-waarde te definiëren die die grootte vereist.
De andere manier is om reguliere int-stijlen te gebruiken in de struct-definities, maar dan ziet men het gemak van de debugger achterwege om de waarde te laten zien op enumnaam, en in plaats daarvan alleen gehele getallen te krijgen.
Dan moet je waarschijnlijk specificeren dat de structuur die de enum bevat verpakt is, niet opgevuld.
Antwoord
Als geen deel van een variabele x
is const
of volatile
, en x
is niet van het type array, dan de verklaring…
x = x;
… doet vrijwel niets. Het is goed gevormd. Ervan uitgaande dat x
vooraf was geïnitialiseerd, ¹ is het ook goed gedefinieerd. De toewijzing is niet t echt de status van het programma veranderen, met een paar mogelijke uitzonderingen (zie hieronder).
Dit is waar zelfs als x
een struct
type.
struct foo {
char buf[42];
int x;
};
struct foo x = { "Hello World", 18 };
x = x; // no big deal.
Dus wat is de “fout”? Het is geen bruikbare code, maar er is nogal wat code die aan die beschrijving voldoet. Het “is slechts een fout als u iets anders wilde doen en u miste.
[Addendum: Gezien de nutteloosheid van deze opdracht, zijn compilers geneigd om ervoor te waarschuwen, aangezien het vrij waarschijnlijk is dat je betekenen iets anders.]
Waarom zoiets over const
en volatile
? De beperking op const
is eenvoudig: het betekent “alleen lezen” en dus kun je er niet naar schrijven. Tenminste, niet met een simpele toewijzing.
Die betreffende volatile
is lastiger. Dat sleutelwoord zegt dat de waarde die erdoor wordt gekwalificeerd, kan worden gewijzigd op manieren die niet zichtbaar zijn voor de implementatie, en dat schrijven ernaar kan bijwerkingen hebben. Zonder hier in een rathole te graven, zien in de praktijk de enige redelijk goed gedefinieerde bewerkingen die u kunt uitvoeren op een vluchtig object er als volgt uit:
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.
Je kunt iets meer dan dat verstandig doen met volatile
, maar slechts in geringe mate. Dat is een onderwerp voor een andere dag. Er is een reden waarom C ++ 20 alle gebruik van volatile
op een paar manieren heeft afgeschaft. Hun veranderingen zien er redelijk verstandig uit.
Ik noemde hierboven een paar mogelijke uitzonderingen. Jonas Oberhauser herinnerde me eraan dat elke opvulling in een struct
niet noodzakelijkerwijs behouden blijft door die toewijzing.
Ook is het theoretisch mogelijk dat de onderliggende representatie voor objecten kan veranderen als gevolg van de toewijzing, als dezelfde waarde op meerdere manieren kan worden weergegeven.
Hopelijk is je programma ongevoelig voor beide mogelijkheden. Als je echter ooit naar de onderliggende weergave van het object kijkt, kun je verschillen zien. Functies zoals memcmp
kunnen dit bijvoorbeeld opmerken. Evenzo als u gebruikt, typ punning.
¹ En als dat niet het geval was, welkom bij ongedefinieerd gedrag, aangezien u waarschijnlijk in aanraking komt met een van deze:
- De waarde van een object met automatische opslagduur wordt gebruikt terwijl deze onbepaald is ( 6.2 .4 , 6.7.9 , 6.8 ).
- Een lvalue die een object aanduidt met een automatische opslagduur die gedeclareerd zou kunnen zijn met de registeropslagklasse, wordt gebruikt in een context die de waarde van het aangewezen object, maar het object is niet geïnitialiseerd. ( 6.3.2.1 ).