¿Dónde encontrar la definición completa de tipo off_t?

8 minutos de lectura

avatar de usuario
Cuatro de un tipo

Estoy enviando un archivo del cliente al servidor usando TCP. Para marcar el final del archivo, me gusta enviar el tamaño del archivo antes de los datos reales. entonces uso stat llamada al sistema para encontrar el tamaño del archivo. Este es de tipo off_t. Me gusta saber cuántos bytes ocupa para poder 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 ser off_t. donde buscar __off_t? También es 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 mejor un archivo de encabezado?

#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 

  • Cualquier cosa que comience con __ está reservado para el uso de la 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 nada que puedas hacer legítimamente. Los bits específicos de la plataforma de los encabezados se pueden ocultar mejor (por lo que una sola copia del código fuente puede manejar compilaciones de 32 bits y 64 bits en una sola máquina, por ejemplo). Leer encabezados estándar es una tarea importante porque hay muchas definiciones interrelacionadas.

    –Jonathan Leffler

    31 de enero de 2012 a las 3:04

avatar de usuario
timoteo jones

Dado que esta respuesta aún se vota, quiero señalar que casi nunca debería necesitar buscar en los archivos de encabezado. Si desea escribir un código confiable, es mucho mejor que busque en el estándar. Entonces, la respuesta a “¿dónde puedo encontrar la definición completa de off_t” está “en un archivo estándar, en lugar de un encabezado”. 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 puedes navegar aquí.

Desafortunadamente, off_t no está muy rigurosamente definido. Todo lo que pude encontrar para definirlo está en la página en sys/types.h:

blkcnt_t y off_t serán tipos enteros con signo.

Esto significa que no puedes estar seguro de qué tan grande es. Si está usando GNU C, puede usar las instrucciones en la respuesta a continuación para asegurarse de que sea de 64 bits. O mejor, puede convertirlo a un tamaño estándar definido antes de colocarlo en el cable. Así funcionan proyectos como el de Google Búferes de protocolo trabajo (aunque ese es un proyecto de C++).


Para completar, aquí está la respuesta a “qué archivo de encabezado define off_t?”:

En mi máquina (y en la mayoría de las máquinas que usan glibc) encontrará la definición en bits/types.h (como dice un comentario en la parte superior, nunca incluya directamente este archivo), pero está un poco oculto en un montón de macros. Una alternativa a intentar desentrañarlos es mirar 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 quieres saber el tamaño de algo, siempre puedes usar el sizeof() operador.

Editar: Acabo de ver la parte de tu pregunta sobre el __. Esta respuesta tiene una buena discusión. El punto clave es que los nombres que comienzan con __ están reservados para la implementación (por lo que no debe comenzar sus propias definiciones con __).

  • Uso el tamaño de on off_t. En mi máquina (cliente) son 4 bytes. Entonces, 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.

    – Cuatro de un tipo

    31 de enero de 2012 a las 2:54

  • Eso es verdad off_t pueden 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 8 bytes off_t y size_t definiciones

    – Timoteo Jones

    31 de enero de 2012 a las 2:57

  • Bien. Entonces, ¿qué debe buscar el servidor en los primeros 4 o los primeros 8 bytes para obtener la longitud del archivo?

    – Cuatro de un tipo

    31 de enero de 2012 a las 2:59


  • Bien, lo tengo. Debería usar un valor más grande como long long, que garantiza que sea el mismo en la máquina y luego lo envíe para enviarlo al servidor.

    – Cuatro de un tipo

    31 de enero de 2012 a las 3:04

  • No se garantiza que long long sea del mismo tamaño en dos máquinas; el tamaño exacto no está estandarizado.

    – Timoteo Jones

    31 de enero de 2012 a las 3:06


avatar de usuario
gustar

Como dice el “Manual de referencia de la biblioteca 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.

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 desea una forma confiable de representar el tamaño del archivo entre el cliente y el servidor, puede:

  1. Utilizar off64_t tipo y stat64() funcionar en consecuencia (ya que llena la estructura stat64que contiene off64_t escriba en sí mismo). Escribe off64_t garantiza el mismo tamaño en máquinas de 32 y 64 bits.
  2. Como se mencionó antes compilar tu codigo con -D_FILE_OFFSET_BITS == 64 y uso habitual off_t y stat().
  3. Convertir off_t digitar int64_t con tamaño fijo (estándar C99).
    Nota: (mi libro ‘C en pocas palabras’ dice que es estándar C99, pero opcional en la implementación). El estándar C11 más nuevo 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 implementació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.

Por lo tanto, en general, el estándar C no puede garantizar tipos con tamaños fijos. Pero la mayoría de los compiladores (incluido gcc) admiten esta característica.

  • “Este es un tipo de entero con signo que se usa para representar tamaños de archivo”. Si representan el tamaño de los archivos, ¿por qué usar “firmado”?

    – Rodrigo

    20 de abril de 2021 a las 7:07

  • (1) Porque es conveniente devolver valores negativos para indicar errores. (2) Porque la oración debería decir “Este es un tipo de entero con signo que se usa para representar compensaciones de archivos”, es decir, buscando hacia adelante o hacia atrás.

    – William Cushing

    26 de mayo de 2021 a las 1:26

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 observa la salida completa, incluso puede ver la ubicación exacta del archivo de encabezado y el número de línea donde 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;

Si está escribiendo código portátil, la respuesta es “no se puede decir”, la buena noticia es que no es necesario. Su protocolo debe implicar escribir el tamaño como (por ejemplo) “8 octetos, formato big-endian” (idealmente con una verificación de que el tamaño real cabe en 8 octetos).

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad