Подтвердить что ты не робот

Где найти полное определение типа off_t?

Я отправляю файл с клиента на сервер с помощью 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 
4b9b3361

Ответ 1

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

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

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

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

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


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

Вы найдете определение в 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().

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

Ответ 2

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

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

  • Используйте off64_t тип и stat64() функцию соответственно (поскольку она заполняет структуру stat64, которая содержит тип off64_t). Тип off64_t гарантирует одинаковый размер на 32- и 64-разрядных машинах.
  • Как было упомянуто перед компиляцией вашего кода с помощью -D_FILE_OFFSET_BITS == 64 и используйте обычные off_t и stat().
  • Преобразуйте 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) поддерживают эту функцию.

Ответ 3

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

Ответ 4

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

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

...

# 91 "/usr/include/stdio.h" 3 4
typedef __off_t off_t;