哪里可以找到off_t类型的完整定义?

时间:2012-01-31 02:31:38

标签: c sockets networking types header-files

我正在使用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 个答案:

答案 0 :(得分:68)

由于这个答案仍然被投票,我想指出你几乎不需要查看头文件。如果您想编写可靠的代码,那么通过查看标准可以获得更好的服务。比“我的机器上off_t如何定义”更好的问题是“标准如何定义off_t?”。遵循标准意味着您的代码将在今天和明天在任何计算机上运行。

在这种情况下,{C}标准未定义off_t。它是POSIX标准的一部分,you can browse here

不幸的是,off_t的定义不是很严格。我可以找到定义它的所有内容都在sys/types.h的页面上:

  

blkcnt_toff_t应为有符号整数类型。

这意味着您无法确定它有多大。如果您使用的是GNU C,则可以使用the answer below中的指令确保它是64位。或者更好的是,您可以在将其放入线路之前转换为标准定义的大小。这就是Google Protocol Buffers等项目的工作方式(虽然这是一个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()运算符。

编辑:刚看到关于__的问题部分。 This answer has a good discussion。关键点是以__开头的名称是为实现保留的(因此您不应该使用__开始自己的定义。)

答案 1 :(得分:31)

正如“GNU C Library Reference Manual”所说

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类型本身)。在32位和64位计算机上键入off64_t保证大小相同。
  2. 如前所述,使用-D_FILE_OFFSET_BITS == 64编译您的代码并使用常规off_tstat()
  3. off_t转换为固定大小的int64_t类型(C99标准)。 注意:(我的书'C in a Nutshell'表示它是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.
    
  4. 因此,一般来说,C标准不能保证具有固定大小的类型。但大多数编译器(包括gcc)都支持此功能。

答案 2 :(得分:6)

如果您在跟踪定义时遇到问题,可以使用编译器的预处理输出,它将告诉您需要知道的所有内容。 E.g。

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

答案 3 :(得分:4)

如果您正在编写便携式代码,答案是&#34;您无法告诉&#34;,好消息是您不需要。您的协议应该包括将大小写为(例如)&#34; 8个八位字节,大端格式&#34; (理想情况下检查实际大小是否适合8个八位字节。)