【问题标题】:Where to find the complete definition of off_t type?在哪里可以找到 off_t 类型的完整定义?
【发布时间】:2012-02-22 19:48:30
【问题描述】:

我正在使用 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 

【问题讨论】:

  • 任何以__ 开头的东西都保留给实现使用(除非标准定义了它的含义,如__func____FILE__)。间接级别允许实现定义自己的类型__off_t,而不会干扰您可以合法执行的任何操作。然后可以更好地隐藏标头的特定于平台的位(例如,源代码的单个副本可以在单台机器上处理 32 位和 64 位编译)。阅读标准标题是一项主要工作,因为有很多相互关联的定义。

标签: c sockets networking types header-files


【解决方案1】:

由于这个答案仍然被投票,我想指出您几乎不需要查看头文件。如果您想编写可靠的代码,那么通过查看标准可以为您提供更好的服务。因此,“我在哪里可以找到off_t 的完整定义”的答案是“在标准中,而不是在头文件中”。遵循标准意味着您的代码今天和明天都可以在任何机器上运行。

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

很遗憾,off_t 的定义不是很严格。我能找到的所有定义都在sys/types.h的页面上:

blkcnt_toff_t 应为有符号整数类型。

这意味着您无法确定它有多大。如果您使用的是 GNU C,您可以使用 the answer below 中的说明来确保它是 64 位的。或者更好的是,您可以在将其放在电线上之前将其转换为标准定义的尺寸。这就是像 Google 的 Protocol Buffers 这样的项目的工作方式(尽管那是一个 C++ 项目)。


为了完整起见,这里是“哪个头文件定义off_t?”的答案:

在我的机器(以及大多数使用 glibc 的机器)上,您会在 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。关键是,以__ 开头的名称是为实现保留的(因此您不应以__ 开头自己的定义)。

【讨论】:

  • 我使用 on off_t 的大小。在我的机器(客户端)上它是 4 个字节。所以我可以表示的最大文件大小是 2^32 字节。在这种特殊情况下,这是否必须与我的服务器上的 off_t 大小相匹配。我不应该相信。
  • 确实off_t 在不同的机器(或编译器)上可以有不同的大小。请注意,在 GCC 中,您可以使用 -D_FILE_OFFSET_BITS=64 获取 8 字节 off_tsize_t 定义。
  • 好的。那么服务器应该查找前 4 个或前 8 个字节以获取文件的长度。
  • 好的,我知道了。我应该使用更大的值,比如 long long ,它保证在两台机器上都相同,然后向上转换以将其发送到服务器。
  • long long 不能保证在两台机器上的大小相同 - 确切的大小没有标准化。
【解决方案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.

因此,如果您想要以可靠的方式表示客户端和服务器之间的文件大小,您可以:

  1. 相应地使用off64_t 类型和stat64() 函数(因为它填充了结构stat64,其中包含off64_t 类型本身)。键入 off64_t 保证在 32 位和 64 位机器上的大小相同。
  2. 如前所述,使用-D_FILE_OFFSET_BITS == 64 编译您的代码,并使用通常的off_tstat()
  3. off_t 转换为具有固定大小(C99 标准)的int64_t注意:(我的书'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.

因此,一般来说,C 标准不能保证具有固定大小的类型。但是大多数编译器(包括 gcc)都支持这个特性。

【讨论】:

  • “这是一个用于表示文件大小的有符号整数类型”。如果它们代表文件的大小,那么为什么要使用“签名”?
  • (1) 因为返回负值表示错误很方便。 (2) 因为句子应该说“这是一个有符号整数类型,用来表示文件偏移量”,即向前或向后寻找。
【解决方案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;
    

    【讨论】:

      猜你喜欢
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-07
      • 2010-09-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多