Nejlepší odpověď
Velmi trnitý hlavolam, když člověk musí odpovídat offsetům struktury přes hranice stroje nebo síťové protokoly . Specifikace říká, že velikost musí být minimální, aby představovala největší hodnotu, kterou může mít. Například typický výčet stavu stavového stroje může vyžadovat pouze bajt.
Existují AFAIK pouze třemi způsoby, jak ovládat velikost:
některé (ale ne všechny) kompilátory mají přepínač kompilátoru k vynucení velikosti buď sizeof (int), nebo na 32 bitů. Syntaxe přepínače není stejná mezi příkazy MSC a gccc / clang.
Druhým způsobem, pokud potřebujete vyplnit 16bitové pole, je definovat fiktivní maximální hodnotu, která vyžaduje tuto velikost.
Druhým způsobem je použití běžných int stylů v definicích struktury, ale pak se člověk vzdá pohodlí debuggeru, když má zobrazovat hodnotu podle názvu výčtu, a místo toho získává pouze celá čísla.
Potom bude pravděpodobně potřeba určit, že struktura obsahující výčet je zabalená, nikoli polstrovaná.
Odpověď
Pokud žádná část nějaké proměnné x
je const
nebo volatile
a x
není typu pole, pak tvrzení…
x = x;
… skoro nic nedělá. Je dobře formovaný. Za předpokladu, že x
byl předem inicializován, ¹ je také dobře definován. Přiřazení není Opravdu nezměníte stav programu, s několika potenciálními výjimkami (viz níže).
To platí, i když x
má struct
typ.
struct foo {
char buf[42];
int x;
};
struct foo x = { "Hello World", 18 };
x = x; // no big deal.
Co je tedy „chyba“? Není to užitečný kód, ale je toho docela dost kódu, který tomuto popisu vyhovuje. Je to jen chyba , pokud jste chtěli udělat něco jiného a nestihli jste.
[Dodatek: Vzhledem k zbytečnosti tohoto úkolu jsou kompilátoři nakloněni varovat, protože je to dost pravděpodobné, znamená něco jiného.]
Proč bit o const
a volatile
? Omezení const
je jednoduché: znamená „pouze pro čtení“, takže do něj nemůžete psát. Alespoň ne s jednoduchým přiřazením.
Ten, který se týká volatile
, je složitější. Toto klíčové slovo říká, že hodnota, kterou kvalifikuje, může být upravena způsoby, které nejsou viditelné pro implementaci, a které do ní zapisuje, může mít vedlejší účinky. Aniž byste zde kopali do díry, jediné rozumně dobře definované operace, které můžete na těkavém objektu provést, vypadají takto:
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.
S volatile
můžete udělat něco víc než to, ale jen mírně. To je téma na další den. Existuje důvod, proč C ++ 20 již nepoužívá volatile
kromě několika použití. Jejich změny vypadají docela rozumně.
Výše jsem zmínil několik možných výjimek. Jonas Oberhauser mi připomněl, že jakékoli polstrování v struct
není tímto přiřazením nutně zachováno.
Je také teoreticky možné, že podkladová reprezentace objektů se může změnit kvůli přiřazení, pokud lze stejnou hodnotu znázornit více způsoby.
Doufejme, že váš program není citlivý na obě možnosti. Pokud se však někdy podíváte na podkladovou reprezentaci objektu, můžete vidět rozdíly. Mohou si například všimnout funkce, jako je memcmp
. Podobně pokud zaměstnáváte zadejte punning.
¹ A pokud to tak nebylo, vítejte nedefinované chování, protože pravděpodobně narazíte na jednu z těchto možností:
- Hodnota objektu s automatickou dobou uložení se použije, když je neurčitý ( 6.2 .4 , 6.7.9 , 6.8 ).
- Hodnota lvalue označující objekt s automatickým trváním úložiště, který mohl být deklarován třídou úložiště registru, se používá v kontextu, který vyžaduje hodnota určeného objektu, ale objekt je neinicializován. ( 6.3.2.1 ).