web-dev-qa-db-fra.com

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

J'envoie le fichier du client au serveur en utilisant TCP. Pour marquer la fin du fichier, je souhaite envoyer la taille du fichier avant les données réelles. J'utilise donc stat appel système pour trouver la taille du fichier. C'est du type off_t. J'aime savoir combien d'octets il occupe pour pouvoir le lire correctement côté serveur. Il est défini dans le <sys/types.h>. Mais je ne comprends pas la définition. Cela définit juste __off_t or _off64_t être off_t. Où chercher __off_t? Aussi est-ce convention 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 
59
FourOfAKind

Comme cette réponse est toujours mise aux voix, 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 ferez bien mieux de regarder dans la norme. Une meilleure question que "comment off_t Est défini sur ma machine" est "comment est définie off_t Par le standard?". 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 la norme C. Cela fait partie de la norme POSIX, qui vous pouvez naviguer ici .

Malheureusement, off_t N'est pas défini de manière très rigoureuse. Tout ce que j'ai pu trouver pour le définir se trouve sur la page sur 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 que le format est 64 bits. Sinon, vous pouvez convertir en normes définies. C’est ainsi que fonctionnent des projets tels que celui de Google Protocol Buffers (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, n'incluez jamais directement ce fichier), mais elle est un peu masquée dans un ensemble de macros. Une alternative pour essayer de les démêler est de regarder la sortie du préprocesseur:

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

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: Vous venez de voir 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 à la mise en œuvre (vous ne devriez donc pas commencer vos propres définitions avec __).

71
Timothy Jones

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 compiled 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 voulez 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() en conséquence (car elle remplit la structure stat64, Qui contient le type off64_t Elle-même). Le type off64_t Garantit la même taille sur les ordinateurs 32 et 64 bits.
  2. Comme mentionné précédemment, compilez votre code avec -D_FILE_OFFSET_BITS == 64 Et utilisez les méthodes habituelles off_t Et stat().
  3. Convertissez off_t En type int64_t Avec une taille fixe (norme C99). Note: (mon livre 'C in a Nutshell' indique qu'il s'agit du standard C99, mais optionnel dans son implémentation). 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 <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.
    

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) prennent en charge cette fonctionnalité.

33
likern

Si vous rencontrez des difficultés pour suivre 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 <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) ;

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;
6
chutz

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 devrait impliquer d'écrire la taille sous la forme, par exemple, "8 octets, format big-endian" (idéalement, en vérifiant que la taille réelle est bien adaptée à 8 octets.)

4
Martin Bonner