Domanda

unsigned char a, b;
b = something();
a = ~b;

Un analizzatore statico si è lamentato del troncamento nell'ultima riga, presumibilmente perché b viene promosso a int prima che i suoi bit vengano invertiti e il risultato sarà di tipo int.

Sono interessato solo all'ultimo byte dell'int promosso - se b era 0x55, ho bisogno che a sia 0xAA.La mia domanda è: la specifica C dice qualcosa su come avviene il troncamento o l'implementazione è definita / indefinita?È garantito che a a verrà sempre assegnato il valore che mi aspetto o potrebbe andare storto su una piattaforma conforme?

Ovviamente, il cast del risultato prima dell'assegnazione silenzia l'analizzatore statico, ma voglio sapere se è sicuro ignorare questo avviso in primo luogo.

È stato utile?

Soluzione

Il troncamento avviene come descritto in 6.3.1.3/2 di C99 Standard

... se il nuovo tipo non è firmato, il valore viene convertito aggiungendo o sottraendo ripetutamente uno in più rispetto al valore massimo che può essere rappresentato nel nuovo tipo finché il valore non è compreso nell'intervallo del nuovo tipo.


Esempio per CHAR_BIT== 8, sizeof (unsigned char)== 1, sizeof (int)== 4

Quindi, 0x55 viene convertito in int, in 0x00000055, quindi negato in 0xFFFFFFAA e

      0xFFFFFFAA
    + 0x00000100 /* UCHAR_MAX + 1 */
    ------------
      0xFFFFFEAA

    ... repeat lots and lots of times ...

      0x000000AA

o, come semplice 0xAA, come ti aspetteresti

Altri suggerimenti

Lo standard C specifica questo per i tipi senza segno:

Un calcolo che coinvolge unsigned gli operandi non possono mai traboccare, perché a risultato che non può essere rappresentato da il tipo intero senza segno risultante è ridotto modulo il numero che è uno maggiore del valore più grande that può essere rappresentato dal risultato tipo.

In questo caso, se il tuo unsigned char è di 8 bit, significa che il risultato sarà ridotto modulo 256, il che significa che se b era 0x55, a finirà effettivamente come 0xAA.

Ma nota che se unsigned char è più largo di 8 bit (che è perfettamente legale), otterrai un risultato diverso. Per assicurarti di ottenere in modo portabile 0xAA come risultato, puoi utilizzare:

a = ~b & 0xff;

(Il bit per bit e dovrebbe essere ottimizzato su piattaforme in cui unsigned char è 8 bit).

Nota anche che se utilizzi un tipo con segno, il risultato è definito dall'implementazione.

Si comporterà come vuoi tu.È sicuro eseguire il cast del valore.

Questo particolare esempio di codice è sicuro.Ma ci sono ragioni per mettere in guardia contro un uso lassista dell'operatore ~.

La ragione di ciò è che ~ su piccole variabili intere è un potenziale bug in espressioni più complesse, a causa delle promozioni implicite di interi in C. Immagina di avere un'espressione come

a = ~b >> 4;

Non si sposterà di zero come ci si sarebbe potuto aspettare.

Se il tuo analizzatore statico è impostato per includere MISRA-C, ad esempio riceverai questo avviso per ogni operatore ~, perché MISRA impone che il risultato di qualsiasi operazione su piccoli tipi interi sia tipizzato esplicitamente nel tipo previsto, char non firmatoin questo caso.

Prendiamo il caso della macchina Win32.
Il numero intero è di 4 byte e convertirlo in un carattere risulterà esattamente come se i 3 byte rimanenti fossero stati rimossi.

Poiché stai convertendo un char in char, non importa a cosa viene promosso.
~b will add 3 bytes at the left change 0s to 1 and then remove... It does not affect your one right byte.

Lo stesso concetto sarà applicabile a diverse architetture (che si tratti di macchine a 16 bit o 64 bit)

Supponendo che sia little-endian

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top