2012-01-31 15 views
42

Sto inviando file dal client al server usando TCP. Per contrassegnare la fine del file mi piace inviare la dimensione del file prima dei dati effettivi. Quindi io uso la chiamata di sistema stat per trovare la dimensione del file. Questo è di tipo off_t. Mi piace sapere quanti byte occupa in modo che io possa leggerlo correttamente dal lato server. È definito nello <sys/types.h>. Ma non capisco la definizione. Definisce semplicemente __off_t or _off64_t come off_t. Dove cercare __off_t? Inoltre è convenzione che __ è prefissato per la maggior parte delle cose nei file di intestazione e mi spaventa quando leggo i file di intestazione per capire meglio. Come leggere meglio un file di intestazione?Dove trovare la definizione completa di tipo off_t?

#ifndef __off_t_defined 
# ifndef __USE_FILE_OFFSET64 
typedef __off_t off_t; 
# else 
typedef __off64_t off_t; 
# endif 
# define __off_t_defined 
#endif 
+5

Tutto ciò che inizia con '__' è riservato per l'uso dal implementazione (a meno che lo standard non ne definisca un significato, come in '__func__' o' __FILE__'). Il livello di riferimento indiretto consente all'implementazione di definire il proprio tipo "__off_t" senza interferire con ciò che è legittimo. I bit specifici delle piattaforme delle intestazioni possono quindi essere meglio nascosti (quindi una singola copia del codice sorgente può gestire le compilazioni a 32 e 64 bit su una singola macchina, ad esempio). Leggere le intestazioni standard è un compito importante perché ci sono così tante definizioni interconnesse. –

risposta

54

Dal momento che questa risposta viene comunque votato, voglio sottolineare che si dovrebbe quasi mai bisogno di guardare nei file di intestazione. Se vuoi scrivere un codice affidabile, ti servirà molto meglio guardando nello standard. Una domanda migliore di "come è definito off_t sulla mia macchina" è "come è definito lo standard off_t dallo standard?". Seguire lo standard significa che il tuo codice funzionerà oggi e domani, su qualsiasi macchina.

In questo caso, off_t non è definito dallo standard C. Fa parte dello standard POSIX, che è you can browse here.

Sfortunatamente, off_t non è definito molto rigorosamente. Tutto quello che potevo trovare per definirlo è nella pagina on sys/types.h:

blkcnt_t e off_t è firmato tipi interi.

Ciò significa che non si può essere sicuri di quanto sia grande. Se si utilizza GNU C, è possibile utilizzare le istruzioni in the answer below per assicurarsi che siano 64 bit. O meglio, è possibile convertire in una dimensione definita standard prima di metterlo sul filo. Questo è il modo in cui funzionano progetti come il Protocol Buffers di Google (anche se si tratta di un progetto C++).


Quindi, penso che "dove trovo la definizione nei miei file di intestazione" non è la migliore domanda. Ma, per completezza ecco la risposta:

Troverete la definizione in bits/types.h (come commento dice in alto, non includere direttamente questo file), ma è un po 'oscurata in un mucchio di macro. Un'alternativa a cercare di svelare loro è quello di osservare l'output del preprocessore:

#include <stdio.h> 
#include <sys/types.h> 

int main(void) { 
    off_t blah; 

    return 0; 
} 

E poi:

$ gcc -E sizes.c | grep __off_t 
typedef long int __off_t; 
.... 

Tuttavia, se si desidera conoscere la dimensione di qualcosa, si può sempre utilizzare il sizeof() operatore.

Modifica: Ho appena visto la parte della tua domanda sullo __. This answer has a good discussion. Il punto chiave è che i nomi che iniziano con __ sono riservati per l'implementazione (quindi non si dovrebbero iniziare le proprie definizioni con __).

+0

Uso la dimensione di on_t. Sulla mia macchina (client) sono 4 byte. Quindi la dimensione massima del file che posso rappresentare è 2^32 byte. In questo caso particolare deve corrispondere con la dimensione off_t sul mio server. Non dovrei credere. – FourOfAKind

+1

È vero che 'off_t' può avere dimensioni diverse su macchine diverse (o compilatori).Nota che in GCC puoi usare '-D_FILE_OFFSET_BITS = 64' per ottenere le definizioni di 8 byte' off_t' e 'size_t'. –

+0

Ok.Così cosa deve essere il server a cercare i primi 4 o i primi 8 byte per ottenere la lunghezza del file. – FourOfAKind

26

Come il "Manuale GNU C Library Reference" dice

off_t 
    This is a signed integer type used to represent file sizes. 
    In the GNU C Library, this type is no narrower than int. 
    If the source is compiled with _FILE_OFFSET_BITS == 64 this 
    type is transparently replaced by off64_t. 

e

off64_t 
    This type is used similar to off_t. The difference is that 
    even on 32 bit machines, where the off_t type would have 32 bits, 
    off64_t has 64 bits and so is able to address files up to 2^63 bytes 
    in length. When compiling with _FILE_OFFSET_BITS == 64 this type 
    is available under the name off_t. 

Quindi, se si desidera modo affidabile per rappresentare la dimensione del file tra client e server, è possibile:

  1. Utilizzare il tipo off64_t e la funzione stat64() di conseguenza (poiché riempie la struttura stat64, che contiene lo stesso off64_t). Il tipo off64_t garantisce la stessa dimensione su macchine a 32 e 64 bit.
  2. Come è stato menzionato prima compilare il codice con -D_FILE_OFFSET_BITS == 64 e utilizzare il solito off_t e stat().
  3. Convertire off_t per il tipo int64_t con dimensioni fisse (standard C99). Nota: (il mio libro "C in poche parole" dice che è standard C99, ma facoltativo in fase di implementazione). Lo standard C11 ultimo dice:

    7.20.1.1 Exact-width integer types 
    1 The typedef name intN_t designates a signed integer type with width N , 
    no padding bits, and a two’s complement representation. Thus, int8_t 
    denotes such a signed integer type with a width of exactly 8 bits. 
    without mentioning. 
    

    E in merito all'esecuzione:

    7.20 Integer types <stdint.h> 
    ... An implementation shall provide those types described as ‘‘required’’, 
    but need not provide any of the others (described as ‘‘optional’’). 
    ... 
    The following types are required: 
    int_least8_t uint_least8_t 
    int_least16_t uint_least16_t 
    int_least32_t uint_least32_t 
    int_least64_t uint_least64_t 
    All other types of this form are optional. 
    

Così, in generale, di serie C non può garantire tipi con dimensioni fisse. Ma la maggior parte dei compilatori (incluso gcc) supporta questa funzione.

+2

belle informazioni. +1 – loulou

+0

Ho modificato la risposta in base al tuo commento. Grazie! – likern

2

Se si riscontrano problemi nel tracciare le definizioni, è possibile utilizzare l'output pre-elaborato del compilatore che indicherà tutto ciò che è necessario sapere. Per esempio.

$ cat test.c 
#include <stdio.h> 
$ cc -E test.c | grep off_t 
typedef long int __off_t; 
typedef __off64_t __loff_t; 
    __off_t __pos; 
    __off_t _old_offset; 
typedef __off_t off_t; 
extern int fseeko (FILE *__stream, __off_t __off, int __whence); 
extern __off_t ftello (FILE *__stream) ; 

Se si guarda l'output completo si può anche vedere l'esatto numero di posizione del file di intestazione e la linea dove è stato definito:

# 132 "/usr/include/bits/types.h" 2 3 4 


typedef unsigned long int __dev_t; 
typedef unsigned int __uid_t; 
typedef unsigned int __gid_t; 
typedef unsigned long int __ino_t; 
typedef unsigned long int __ino64_t; 
typedef unsigned int __mode_t; 
typedef unsigned long int __nlink_t; 
typedef long int __off_t; 
typedef long int __off64_t; 

...

# 91 "/usr/include/stdio.h" 3 4 
typedef __off_t off_t; 
3

Se stanno scrivendo un codice portatile, la risposta è "non si può dire", la buona notizia è che non è necessario. Il tuo protocollo dovrebbe comportare la scrittura delle dimensioni come (ad esempio) "8 ottetti, formato big-endian" (Idealmente con un controllo che le dimensioni effettive si adattino in 8 ottetti)

Problemi correlati