2012-03-07 13 views
6

Ho appena letto su mode_t che memorizza fondamentalmente le seguenti informazioni:Perché mode_t usa 4 byte?

  • 7 valori booleani per il tipo di file (S_IFREG, S_IFDIR, S_IFCHR, S_ISBLK, S_ISFIFO, S_ISLINK, S_ISSOCK)
  • 3 * 3 = 9 valori booleani per i permessi di accesso (leggi, scrivi ed esegui per proprietario, gruppo e altri)

Quindi ha bisogno di 16 bit = 2 byte. Suppongo che potresti persino avere un bit in meno per il tipo di file, dato che deve essere un file normale, una directory, un carattere o un dispositivo a blocchi, un socket, un collegamento simbolico o una pipe. O esistono altri tipi di file?

così ho appena controllato le dimensioni del mode_t con

printf("Size: %d byte\n", sizeof(mode_t)); 

Esso utilizza 4 byte. Perché usa 4 byte? C'è qualche informazione aggiuntiva che non ho notato?

edit: ho scoperto che mode_t è definita in ptypes.inc:

type mode_t = cuint32; 

cuint32 è dimensionata a 32 bit, intero senza segno e definita ctypes.inc:

type cuint32 = LongWord; 

Forse questo aiuta per la risposta.

+1

e se è necessario aggiungere più opzioni/contrassegni ecc. In futuro? – Nim

+0

Potrebbe essere che è semplicemente typedef'ed da un 'int', che è 32 bit nella maggior parte delle architetture. O è reso più grande in modo che possa adattarsi alle future bandiere. –

+0

Il tuo ** int ** digita _may_ essere 4 byte anche se memorizzi il numero "255" ... Il "building block" è l'architettura del processore e inoltre hai dello spazio libero per qualsiasi altra bandiera bisogno. OMG odio i bitflags !!! –

risposta

9

Diamo un'occhiata a ciò che un compilatore "stupido" avrebbe fatto quando dato il seguente codice:

#include <stdio.h> 
#include <stdint.h> 

int main(int argc, char **argv) { 
    uint16_t test1 = 0x1122; 
    uint32_t test2 = 0x11223344; 
    if (test1 & 0x0100) 
    printf("yay1.\n"); 
    if (test2 & 0x00010000) 
    printf("yay2.\n"); 
} 

Questo mi sembra un caso d'uso probabile per valori di tipo mode_t, controllando se è impostata una bandiera. Ora si compila con gcc -O0 e controllare l'assembly generato:

0000000000000000 <main>: 
      ... 
    f: 66 c7 45 fe 22 11  movw $0x1122,-0x2(%rbp) 
    15: c7 45 f8 44 33 22 11 movl $0x11223344,-0x8(%rbp) 
    1c: 0f b7 45 fe    movzwl -0x2(%rbp),%eax ; load test1 into %eax 
    20: 25 00 01 00 00   and $0x100,%eax 
    25: 85 c0     test %eax,%eax 
      ... 
    33: 8b 45 f8    mov -0x8(%rbp),%eax ; load test2 into %eax 
    36: 25 00 00 01 00   and $0x10000,%eax 
    3b: 85 c0     test %eax,%eax 
      ... 

Vedere come è necessaria la speciale istruzioni movzwl per caricare il valore a 16 bit? Questo perché ha bisogno di essere esteso al segno a due byte aggiuntivi per adattarsi al registro. Ovviamente questa istruzione è più complessa di un semplice mov. Questo potrebbe avere un impatto minimo sulle prestazioni e potrebbe aumentare la dimensione dell'eseguibile di alcuni byte, il che di per sé non sarebbe un problema.

Tuttavia, se consideriamo che non ci sarebbe alcun vantaggio nell'utilizzo di un valore a 16 bit, perché in genere richiederebbe fino a 32 bit di spazio di archiviazione a causa dell'allineamento, è chiaro il motivo per cui i progettisti hanno scelto di utilizzare la dimensione della parola nativa della CPU qui.