Migliore risposta
Un enigma molto spinoso, quando si devono far corrispondere gli offset della struttura attraverso i confini della macchina o i protocolli di rete . La specifica dice che la dimensione deve essere il minimo richiesto per rappresentare il valore massimo che può assumere. Quindi una tipica enumerazione dello stato di una macchina a stati, ad esempio, potrebbe richiedere solo un byte.
Ci sono solo tre modi per controllare la dimensione:
alcuni (ma non tutti) i compilatori hanno unopzione del compilatore per forzare la dimensione a sizeof (int) oa 32 bit. La sintassi dello switch non è la stessa tra diciamo MSC e gccc / clang.
Il secondo modo, se devi riempire, diciamo, un campo a 16 bit, è definire un valore massimo fittizio che richiede quella dimensione.
Laltro modo è usare i normali stili int nelle definizioni della struttura, ma poi si rinuncia alla comodità del debugger di mostrare il valore in base al nome dellenumerazione e ottenere invece solo numeri interi.
Quindi, probabilmente sarà necessario specificare che la struttura contenente lenum è compressa, non riempita.
Risposta
Se nessuna parte di qualche variabile x
è const
o volatile
e x
non è di tipo array, quindi listruzione …
x = x;
… praticamente non fa nulla. È ben formato. Supponendo che x
sia stato inizializzato in precedenza, ¹ è anche ben definito. Lassegnazione non ” t cambiare davvero lo stato del programma, con un paio di potenziali eccezioni (vedi sotto).
Questo è vero anche se x
ha un struct
tipo.
struct foo {
char buf[42];
int x;
};
struct foo x = { "Hello World", 18 };
x = x; // no big deal.
Allora qual è l “errore”? “Non è un codice utile , ma cè un bel po di codice che si adatta a questa descrizione. “È solo un errore se stavi mirando a fare qualcosaltro e ti sei perso.
[Addendum: data linutilità di questo compito, i compilatori sono inclini a metterlo in guardia, poiché è molto probabile che tu lo facessi significa qualcosaltro.]
Perché la parte su const
e volatile
? La restrizione su const
è semplice: significa “sola lettura” e quindi non puoi “scrivere”. Almeno, non con un semplice compito.
Quello relativo a volatile
è più complicato. Quella parola chiave dice che il valore da essa qualificato potrebbe essere modificato in modi non visibili allimplementazione e che la scrittura su di essa potrebbe avere effetti collaterali. Senza scavare in un rathole qui, in pratica le uniche operazioni ragionevolmente ben definite che puoi eseguire su un oggetto volatile sono simili a questa:
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.
Puoi fare di più con volatile
, ma solo leggermente. Questo è un argomento per un altro giorno. Cè una ragione per cui C ++ 20 ha deprecato tutti gli usi di volatile
tranne alcuni. I loro cambiamenti sembrano abbastanza sensati.
Ho menzionato un paio di possibili eccezioni sopra. Jonas Oberhauser mi ha ricordato che qualsiasi riempimento in un struct
non è necessariamente preservato da quellassegnazione.
Inoltre, è teoricamente possibile che la rappresentazione sottostante per gli oggetti possa cambiare a causa dellassegnazione, se lo stesso valore può essere rappresentato in più modi.
Si spera che il tuo programma sia insensibile a entrambe le possibilità. Tuttavia, se guardi la rappresentazione sottostante delloggetto, potresti notare delle differenze. Ad esempio, potrebbero notare funzioni come memcmp
. Allo stesso modo, se utilizzi digita giochi di parole.
¹ E in caso contrario, benvenuto in comportamento indefinito, perché probabilmente ti scontri con uno di questi:
- Il valore di un oggetto con durata di memorizzazione automatica viene utilizzato mentre è indeterminato ( 6.2 .4 , 6.7.9 , 6.8 ).
- Un lvalue che designa un oggetto di durata di memorizzazione automatica che avrebbe potuto essere dichiarato con la classe di memorizzazione del registro viene utilizzato in un contesto che richiede il valore delloggetto designato, ma loggetto non è inizializzato. ( 6.3.2.1 ).