Où trouver la définition complète du type off_t?

J’envoie un fichier du client au serveur en utilisant TCP. Pour marquer la fin du fichier, j’aime envoyer la taille du fichier avant les données réelles. J’utilise donc l’appel système stat pour trouver la taille du fichier. C’est de type off_t . J’aime savoir combien d’octets il occupe afin que je puisse le lire correctement du côté du serveur. Il est défini dans . Mais je ne comprends pas la définition. Il définit simplement __off_t or _off64_t pour être off_t . Où chercher __off_t ? Aussi est-il conventionnel que __ est préfixé pour la plupart des choses dans les fichiers d’en-tête et me fait peur quand je lis les fichiers d’en-tête pour mieux comprendre. Comment mieux lire un fichier d’en-tête?

 #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 

Étant donné que cette réponse est toujours votée, je tiens à souligner que vous ne devriez presque jamais avoir besoin de regarder dans les fichiers d’en-tête. Si vous voulez écrire du code fiable, vous êtes beaucoup mieux servi en consultant le standard. Une meilleure question que “comment est-ce que off_t est défini sur ma machine” est “comment off_t est- off_t défini par la norme?”. Suivre la norme signifie que votre code fonctionnera aujourd’hui et demain, sur n’importe quelle machine.

Dans ce cas, off_t n’est pas défini par le standard C. Cela fait partie de la norme POSIX, que vous pouvez parcourir ici .

Malheureusement, off_t n’est pas très rigoureusement défini. Tout ce que j’ai pu trouver pour le définir se trouve sur la page de sys/types.h :

blkcnt_t et off_t doivent être des types entiers signés.

Cela signifie que vous ne pouvez pas être sûr de sa taille. Si vous utilisez GNU C, vous pouvez utiliser les instructions de la réponse ci-dessous pour vous assurer qu’il s’agit de 64 bits. Ou mieux, vous pouvez convertir à un format défini avant de le mettre sur le fil. Voilà comment fonctionnent des projets tels que les protocoles Protocol Protocol de Google (bien que ce soit un projet C ++).


Donc, je pense que “où trouver la définition dans mes fichiers d’en-tête” n’est pas la meilleure question. Mais, pour être complet, voici la réponse:

Vous trouverez la définition dans bits/types.h (comme le dit un commentaire en haut, n’incluez jamais directement ce fichier), mais il est un peu caché dans un tas de macros. Une alternative à essayer de les démêler consiste à regarder la sortie du préprocesseur:

 #include  #include  int main(void) { off_t blah; return 0; } 

Et alors:

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

Cependant, si vous voulez connaître la taille de quelque chose, vous pouvez toujours utiliser l’opérateur sizeof() .

Edit: Juste vu la partie de votre question sur le __ . Cette réponse a une bonne discussion . Le point clé est que les noms commençant par __ sont réservés à l’implémentation (vous ne devriez donc pas commencer vos propres définitions avec __ ).

Comme le dit le “Manuel de référence de la bibliothèque GNU C”

 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 comstackd with _FILE_OFFSET_BITS == 64 this type is transparently replaced by off64_t. 

et

 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. 

Ainsi, si vous souhaitez un moyen fiable de représenter la taille du fichier entre le client et le serveur, vous pouvez:

  1. Utilisez le type off64_t et la fonction stat64() conséquence (car il remplit la structure stat64 , qui contient le type off64_t lui-même). Type off64_t garantit la même taille sur les machines 32 et 64 bits.
  2. Comme mentionné précédemment, comstackz votre code avec -D_FILE_OFFSET_BITS == 64 et utilisez les fonctions off_t et stat() habituelles.
  3. Convertissez off_t en type int64_t avec une taille fixe (norme C99). Note: (mon livre “C in a Nutshell” dit qu’il s’agit de la norme C99, mais facultatif dans la mise en œuvre). La nouvelle norme C11 dit:

     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. 

    Et à propos de la mise en œuvre:

     7.20 Integer types  ... 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. 

Ainsi, en général, le standard C ne peut pas garantir les types avec des tailles fixes. Mais la plupart des compilateurs (y compris gcc) supportent cette fonctionnalité.

Si vous rencontrez des difficultés pour tracer les définitions, vous pouvez utiliser la sortie prétraitée du compilateur qui vous indiquera tout ce que vous devez savoir. Par exemple

 $ cat test.c #include  $ 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) ; 

Si vous regardez la sortie complète, vous pouvez même voir l’emplacement exact du fichier d’en-tête et le numéro de ligne où il a été défini:

 # 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; 

Si vous écrivez du code portable, la réponse est “vous ne pouvez pas le dire”, la bonne nouvelle est que vous n’en avez pas besoin. Votre protocole doit impliquer l’écriture de la taille (par exemple) “format 8 octets, big-endian” (idéalement avec une vérification de la taille réelle de 8 octets.)