Где найти полное определение типа 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
Ответы
Ответ 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;