Bedste svar
En meget tornet gåde, når man skal matche strukturforskydninger på tværs af maskingrænser eller netværksprotokoller . Specifikationen siger, at størrelsen skal være det minimum, der kræves for at repræsentere den største værdi, den kan tage. Så en typisk tilstandsmaskinstatus enum, for eksempel, kræver muligvis kun en byte.
Der er kun AFAIK tre måder at kontrollere størrelsen på:
nogle (men ikke alle) kompilatorer har en kompilatorafbryder til at tvinge størrelsen til enten størrelse af (int) eller til 32 bit. Switch-syntaksen er ikke den samme mellem siger MSC og gccc / clang.
Den anden måde, hvis du har brug for at udfylde siger et 16-bit felt, er at definere en dummy max-værdi, der kræver den størrelse.
Den anden måde er at bruge regelmæssige int-stilarter i strukturdefinitionerne, men så giver man afkald på fejlfindingsbekvemmeligheden ved at få den til at vise værdien ved enumnavn og kun få heltal i stedet.
Derefter vil man sandsynligvis skulle specificere strukturen, der indeholder enum, er pakket, ikke polstret.
Svar
Hvis ingen del af en eller anden variabel x
er const
eller volatile
, og x
er ikke af array-typen, så gør udsagnet …
x = x;
… stort set intet. Det er godt dannet. Under forudsætning af at x
var initialiseret på forhånd, ¹ er det også veldefineret. Opgaven gør ikke ikke virkelig ændre programmets tilstand med et par potentielle undtagelser (se nedenfor).
Dette gælder, selvom x
har en struct
type.
struct foo {
char buf[42];
int x;
};
struct foo x = { "Hello World", 18 };
x = x; // no big deal.
Så hvad er “fejlen”? Det er ikke nyttigt kode, men der er en hel del kode, der passer til beskrivelsen. Det er kun en fejl , hvis du sigter mod at gøre noget andet og savnede.
[Addendum: I betragtning af denne opgaves ubrugelighed er kompilatorer tilbøjelige til at advare om det, da det er ret sandsynligt, at du gjorde betyder noget andet.]
Hvorfor lidt om const
og iv id = “3bb41f7bd8” Begrænsningen på const
er enkel: det betyder “skrivebeskyttet”, så du kan ikke skrive til det. I det mindste ikke med simpel tildeling.
Den der vedrører volatile
er vanskeligere. Dette nøgleord siger, at den værdi, der kvalificeres af det, kan ændres på måder, der ikke er synlige for implementeringen, og at skrivning til det kan have bivirkninger. Uden at grave i et rathole her ser de eneste rimeligt veldefinerede operationer, du kan udføre på et flygtigt objekt, i praksis sådan ud:
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øre lidt mere end det fornuftigt med volatile
, men kun lidt. Det er et emne for en anden dag. Der er en grund til, at C ++ 20 udfasede alle undtagen et par anvendelser af volatile
. Deres ændringer ser ret fornuftige ud.
Jeg nævnte et par mulige undtagelser ovenfor. Jonas Oberhauser mindede mig om, at enhver polstring i en struct
er ikke nødvendigvis bevaret af denne opgave.
Det er også teoretisk muligt, at underliggende repræsentation for objekter kan ændre sig på grund af tildelingen, hvis den samme værdi kan repræsenteres flere måder.
Forhåbentlig er dit program ufølsomt for begge muligheder. Hvis du nogensinde ser på den underliggende repræsentation af objektet, kan du dog se forskelle. Funktioner som memcmp
bemærker f.eks. Muligvis. Ligeledes hvis du anvender type punning.
¹ Og hvis det ikke var, velkommen til udefineret adfærd, som du sandsynligvis kæmper med en af disse:
- Værdien af et objekt med automatisk lagringsvarighed bruges, mens det er ubestemt ( 6.2 .4 , 6.7.9 , 6.8 ).
- En værdi, der angiver et objekt med automatisk lagringsvarighed, der kunne have været erklæret med registerlagerklassen, bruges i en sammenhæng, der kræver værdi af det udpegede objekt, men objektet er ikke-initialiseret. ( 6.3.2.1 ).