Где найти полное определение типа off_t? - PullRequest
58 голосов
/ 31 января 2012

Я отправляю файл с клиента на сервер по протоколу TCP. Чтобы отметить конец файла, я хотел бы отправить размер файла до фактических данных. Поэтому я использую системный вызов stat, чтобы найти размер файла. Это типа off_t. Мне нравится знать, сколько байтов он занимает, чтобы я мог правильно прочитать его на стороне сервера. Это определено в <sys/types.h>. Но я не понимаю определения. Он просто определяет __off_t or _off64_t как off_t. Где искать __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 

Ответы [ 4 ]

70 голосов
/ 31 января 2012

Поскольку за этот ответ все еще голосуют, я хочу отметить, что вам почти никогда не нужно заглядывать в заголовочные файлы.Если вы хотите написать надежный код, вам гораздо лучше, если смотреть в стандарт.Лучший вопрос, чем «как определяется off_t на моей машине», это «как определяется off_t стандартом?».Следование стандарту означает, что ваш код будет работать сегодня и завтра на любой машине.

В этом случае off_t не определено стандартом C.Это часть стандарта POSIX, который вы можете просмотреть здесь .

К сожалению, off_t не очень строго определен.Все, что я мог найти, чтобы определить это, на странице sys/types.h:

blkcnt_t и off_t должны быть целочисленными типами со знаком.

Это означает, что вы не можете быть уверены, насколько он велик.Если вы используете GNU C, вы можете использовать инструкции в ответе ниже , чтобы убедиться, что он 64-битный.Или лучше, вы можете преобразовать в размер, определенный стандартами, прежде чем положить его на провод.Вот как работают такие проекты, как Protocol Buffers от Google (хотя это проект C ++).


Итак, я думаю, "где я могу найти определение в моих заголовочных файлах"?это не лучший вопрос.Но, для полноты, вот ответ:

Вы найдете определение в bits/types.h (как говорится в комментарии сверху, никогда не включайте этот файл напрямую), но оно немного затенено в куче макросов,Альтернатива попыткам их распутать - посмотреть на вывод препроцессора:

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

int main(void) {
  off_t blah;

  return 0;
}

А затем:

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

Однако, если вы хотите узнать размер чего-либо, вы можетевсегда используйте оператор sizeof().

Редактировать: только что увидел часть вашего вопроса о __. Этот ответ имеет хорошее обсуждение .Ключевым моментом является то, что имена, начинающиеся с __, зарезервированы для реализации (поэтому вы не должны начинать свои собственные определения с __).

32 голосов
/ 16 января 2013

Как сказано в «Справочном руководстве по библиотекам 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.

и

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.

Таким образом, если вам нужен надежный способ представления размера файла между клиентом и сервером, вы можете:

  1. Используйте тип off64_t и функцию stat64() соответственно (так как она заполняет структуру stat64, которая содержит сам тип off64_t).Тип off64_t гарантирует одинаковый размер на 32- и 64-битных компьютерах.
  2. Как уже упоминалось ранее, скомпилируйте ваш код с -D_FILE_OFFSET_BITS == 64 и используйте обычные off_t и stat().
  3. Преобразование off_t в тип int64_t с фиксированным размером (стандарт C99). Примечание: (моя книга 'C в двух словах' говорит, что это стандарт C99, но не обязательный в реализации).Новейший стандарт C11 гласит:

    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.
    

    А о реализации:

    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.
    

Таким образом, в общем, стандарт C не может гарантировать типы с фиксированными размерами.Но большинство компиляторов (включая gcc) поддерживают эту функцию.

6 голосов
/ 29 мая 2014

Если у вас возникли проблемы с отслеживанием определений, вы можете использовать предварительно обработанные выходные данные компилятора, которые сообщат вам все, что вам нужно знать.Например,

$ 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) ;

Если вы посмотрите на полный вывод, вы даже сможете увидеть точное местоположение файла заголовка и номер строки, где он был определен:

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

...

** 1008
4 голосов
/ 20 августа 2014

Если вы пишете переносимый код, ответ «вы не можете сказать», хорошая новость в том, что вам это не нужно.Ваш протокол должен включать в себя запись размера в виде (например) «8 октетов, формат с прямым порядком байтов» (в идеале с проверкой того, что фактический размер соответствует 8 октетам.)

...