2012-01-31 12 views
42

Estoy enviando archivos de cliente a servidor usando TCP. Para marcar el final del archivo, me gusta enviar el tamaño del archivo antes de los datos reales. Entonces utilizo la llamada al sistema stat para encontrar el tamaño del archivo. Esto es del tipo off_t. Me gusta saber cuántos bytes ocupa para que pueda leerlo correctamente en el lado del servidor. Se define en el <sys/types.h>. Pero no entiendo la definición. Simplemente define __off_t or _off64_t como off_t. ¿Dónde buscar __off_t? También es una convención que __ tiene el prefijo para la mayoría de las cosas en los archivos de encabezado y me asusta cuando leo los archivos de encabezado para comprender mejor. ¿Cómo leer un archivo de cabecera mejor?¿Dónde encontrar la definición completa de off_t type?

#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

Todo lo que empiece por '__' está reservado para el uso por implementación (a menos que el estándar defina un significado para él, como en '__func__' o' __FILE__'). El nivel de indirección permite que la implementación defina su propio tipo '__off_t' sin interferir con cualquier cosa que legítimamente pueda hacer. Los bits específicos de la plataforma de los encabezados pueden ocultarse mejor (por lo que una copia única del código fuente puede manejar compilaciones de 32 y 64 bits en una sola máquina, por ejemplo). Leer encabezados estándar es una tarea importante porque hay tantas definiciones interrelacionadas. –

Respuesta

54

Dado que esta respuesta aún se vota, quiero señalar que casi nunca debería tener que buscar en los archivos de encabezado. Si desea escribir un código confiable, lo mejor será que consulte el estándar. Una pregunta mejor que "cómo se define off_t en mi máquina" es "¿cómo se define el estándar off_t?". Seguir el estándar significa que su código funcionará hoy y mañana, en cualquier máquina.

En este caso, off_t no está definido por el estándar C. Es parte del estándar POSIX, que es you can browse here.

Desafortunadamente, off_t no está definido muy rigurosamente. Todo lo que podía encontrar para definirla es en la página en sys/types.h:

blkcnt_t y off_t será firmada tipos enteros.

Esto significa que no puede estar seguro de lo grande que es. Si está utilizando GNU C, puede usar las instrucciones en the answer below para asegurarse de que sean 64 bits. O mejor, puede convertir a un tamaño estándar definido antes de ponerlo en el cable. Así es como funcionan proyectos como el Protocol Buffers de Google (aunque se trata de un proyecto de C++).


Por lo tanto, yo pienso "¿dónde puedo encontrar la definición en mis archivos de cabecera" no es la mejor pregunta. Pero, para lo completo aquí está la respuesta:

Encontrará la definición de bits/types.h (como dice un comentario en la parte superior, nunca incluya directamente este archivo), pero es un poco oscurecida en un montón de macros. Una alternativa a tratar de desentrañar ellos es mirar a la salida del preprocesador:

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

int main(void) { 
    off_t blah; 

    return 0; 
} 

Y luego:

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

Sin embargo, si usted quiere saber el tamaño de algo, siempre se puede utilizar el sizeof() operador.

Editar: Acabo de ver la parte de tu pregunta sobre el __. This answer has a good discussion. El punto clave es que los nombres que comienzan con __ están reservados para la implementación (por lo que no debe iniciar sus propias definiciones con __).

+0

Uso el tamaño de on off_t. En mi máquina (cliente) es de 4 bytes. El tamaño máximo de archivo que puedo representar es 2^32 bytes. ¿Eso tiene que coincidir con el tamaño off_t en mi servidor en este caso particular? No debería creer. – FourOfAKind

+1

Es cierto que 'off_t' puede tener diferentes tamaños en diferentes máquinas (o compiladores).Tenga en cuenta que en GCC puede usar '-D_FILE_OFFSET_BITS = 64' para obtener definiciones de 8 bytes' off_t' y 'size_t'. –

+0

Ok. ¿Qué debería buscar el servidor primero 4 o primeros 8 bytes para obtener la longitud del archivo? – FourOfAKind

26

Como el "Manual de GNU C Biblioteca de Referencia" 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. 

y

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. 

Por lo tanto si usted quiere manera fiable de lo que representa el tamaño del archivo entre el cliente y el servidor, se puede:

  1. Utilice off64_t tipo y stat64() funcione en consecuencia (ya que rellena la estructura stat64, que contiene el tipo off64_t en sí). El tipo off64_t garantiza el mismo tamaño en máquinas de 32 y 64 bits.
  2. Como se mencionó antes compile su código con -D_FILE_OFFSET_BITS == 64 y use off_t y stat().
  3. Convertir off_t al tipo int64_t con el tamaño fijo (C99 estándar). Nota: (mi libro 'C in a Nutshell' dice que es estándar C99, pero opcional en la implementación). El estándar más reciente C11 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. 
    

    y sobre la aplicación:

    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. 
    

Así, en general, estándar de C no puede garantizar tipos con tamaños fijos. Pero la mayoría de los compiladores (incluido gcc) admiten esta función.

+2

buena información. +1 – loulou

+0

He editado la respuesta de acuerdo con su comentario. ¡Gracias! – likern

2

Si tiene problemas para rastrear las definiciones, puede usar la salida preprocesada del compilador que le dirá todo lo que necesita saber. P.ej.

$ 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 nos fijamos en la salida completa incluso se puede ver la ubicación del archivo de cabecera y la línea número exacto en el que se definió:

# 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

Si están escribiendo código portátil, la respuesta es "no se puede saber", la buena noticia es que no es necesario. Su protocolo debe implicar escribir el tamaño como (por ejemplo) "8 octetos, formato big-endian" (lo ideal sería comprobar que el tamaño real cabe en 8 octetos).

Cuestiones relacionadas