2009-04-30 2 views
11

Stavo facendo un esercizio universitario in cui dovevo restituire un valore con exit, quel valore era in realtà un conteggio di qualcosa. Questo potrebbe essere superiore a 255 (che exit() non può gestire) ma l'insegnante ha suggerito di utilizzare i dati di test in cui il conteggio non potrebbe mai superare tale valore.Qualsiasi vantaggio nell'utilizzo della macro WEXITSTATUS in C su divisione per 256 in stato exit()?

Dopo tutto ciò, ho dovuto gestire questo valore di conteggio, lo stato di uscita, ho ottenuto questo valore nel processo principale utilizzando waitpid(). Con mia sorpresa, se il processo figlio restituiva 1, il valore "reale" nel processo principale era 256, 2 era 512 e così via ...

Avevo bisogno di stampare questo valore così l'ho semplicemente diviso per 256 e era fatto. Tuttavia, se uso la macro WEXITSTATUS(), sarò anche ottenere questo valore il modo in cui lo voglio ...

ho guardato il codice sorgente C e questo è quello che ho scoperto:

#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8) 

Capisco cosa sta succedendo qui, per esempio, 512 in binario è 10 0000 0000, lo spostamento di 8 o il diritto darà 00 0000 0010, che è 2 in decimale. Quello che non capisco in questa macro è l'operatore & e il fatto che 0xff00 sembra un numero casuale (probabilmente non lo è, da dove viene però?). Che cosa fa esattamente questo, perché c'è "& 0xff00" nella macro? Non funzionerebbe senza di esso?

E la vera domanda in questo argomento è la stessa cosa chiamare questa macro nel mio codice come dividendo per 256?

risposta

16

E il vero problema in questo argomento, è la stessa cosa per chiamare questa macro nel mio codice come dividendo per 256?

Probabilmente funzionerà sempre nei casi in cui il processo figlio termina normalmente (cioè chiamando exit(), non per un errore di segmentazione, errore di asserzione, ecc.).

Lo stato memorizzato da waitpid() codifica sia il motivo per cui il processo figlio è stato terminato sia il codice di uscita. Il motivo viene memorizzato nel byte meno significativo (ottenuto da status & 0xff) e il codice di uscita viene memorizzato nel byte successivo (mascherato da status & 0xff00 ed estratto da WEXITSTATUS()). Quando il processo termina normalmente, il motivo è 0 e quindi WEXITSTATUS equivale semplicemente a spostarsi di 8 (o dividere per 256). Tuttavia, se il processo viene ucciso da un segnale (come SIGSEGV), non esiste un codice di uscita e devi utilizzare WTERMSIG per estrarre il numero del segnale dal byte del motivo.

2

Qui 0xff00 è una maschera binaria (link text). ANDing con un valore imposta tutti i bit a zero, tranne il secondo byte (contando da destra).

È necessario utilizzare solo WEXITSTATUS in un processo che è noto per essere uscito normalmente. Questa informazione è data dalla macro WIFEXITED.

E la vera domanda in questo argomento è la stessa cosa chiamare questa macro nel mio codice come dividendo per 256?

La macro rende il codice più leggibile, ed è garantita per lavorare su qualsiasi implementazione conforme a POSIX. Per quanto ne so, Posix non specifica il formato dello stato, quindi non puoi aspettarti che il tuo codice funzioni ovunque.

3

Se la variabile di stato è un numero intero a 16 bit con segno (un 'breve') su una macchina in cui 'int' è una quantità a 32 bit e se lo stato di uscita è nell'intervallo 128..255, quindi WEXITSTATUS() ti dà ancora un valore corretto dove la divisione per 256 o semplicemente lo spostamento a destra ti darà un valore errato.

Questo perché il cortocircuito sarà esteso a 32 bit e il mascheramento annulla l'estensione del segno, lasciando il valore corretto (positivo) nel risultato.

Se la macchina utilizzata interi a 16 bit, quindi il codice a WEXITSTATUS() probabilmente non SHIFT e quindi mascherare per garantire un comportamento simile:

#define WEXITSTATUS(status) (((status)>>8) & 0xFF) 

È perché l'implementazione si prende cura di questi dettagli per voi che dovresti usare la macro WEXITSTATUS().

3

Per quanto posso dire dalla verifica della Unix Spec singolo, il sistema accade per memorizzare lo stato di uscita in ottetto seconda a destra, ma non credo the standard fa. Quindi, è necessario utilizzare i macro per almeno alcuni motivi:

  • Sono corretti. Lo spostamento di bit di un numero negativo fa cose diverse su piattaforme diverse. Funziona come vuoi tu? Non lo so.
  • Sono semplici. È immediatamente chiaro cosa fa WEXITSTATUS. Meno con altri approcci. Se hai visto la versione arrotolata a mano di WIFSIGNALED, la riconosceresti? Quanto tempo ci vorrà più di WIFSIGNALED.
  • Sono portatili. Dal momento che la specifica dice di farlo, funzionerà su tutti i sistemi (almeno praticamente su ogni sistema simile a Unix).