类型后跟_t(下划线-t)代表什么?

Kev*_*fin 240 c types naming-conventions

这似乎是一个简单的问题,但我无法通过Stack Overflow搜索或Google找到它.什么类型后跟一个_t意思?如

int_t anInt;
Run Code Online (Sandbox Code Playgroud)

我在C代码中看到很多意味着与硬件紧密相关 - 我不禁认为它们是相关的.

Jon*_*ler 196

正如Douglas Mayle所说,它基本上表示一个类型名称.因此,使用' _t' 结束变量或函数名称是不明智的,因为它可能会引起一些混淆.还有size_t,在C89标准定义wchar_t,off_t,ptrdiff_t,,可能有一些人我已经忘记了.C99标准定义了很多额外的类型,如uintptr_t,intmax_t,int8_t,uint_least16_t,uint_fast32_t,等.这些新类型是正式定义的,<stdint.h>但大多数情况下,您将使用<inttypes.h>哪些(不常用于标准C头)包含<stdint.h>.它(<inttypes.h>)还定义了与printf()和一起使用的宏scanf().

正如Matt Curtis所说,后缀中的编译器没有意义; 这是一个以人为本的会议.

但是,您还应注意POSIX定义了许多以' _t' 结尾的额外类型名称,并为实现保留了后缀.这意味着如果您正在处理与POSIX相关的系统,那么使用约定定义您自己的类型名称是不明智的.我工作的系统已经完成了(超过20年); 我们经常会被定义与我们定义的名称相同的类型的系统绊倒.

  • 我在typedefs上使用_type而不是_t来避免这种情况. (16认同)
  • @Andrew:如果你有一个方便的缩写用作前缀,那么你可以安全地使用`abbr_xxxxx_t`类型名称.如果没有这样的前缀,您可能会随时被抓住.通常,标准化的`_t`类型使用全部小写(`FILE`和'DIR`是两个例外,两次 - 全部大写,没有`_t`),所以你可以使用具有中等安全性的`CamelCase_t`,或者没有领先的帽子.我主要处理的系统往往生活危险并且无论如何都使用`_t`,但它偶尔会咬我们.我倾向于使用`CamelCase`而没有后缀用于我自己的工作; 我的功能通常都是小写的. (13认同)
  • @JonathanLeffler,我已经开始使用该约定,CamelCase用于类型,lower_case用于函数.我搜索了这个问题,希望我不是唯一一个.谢谢你的验证! (5认同)
  • OS和公共运行时库定义具有通用名称的类型似乎是合理的; 但是你的公司的类型不应该带有前缀或其他东西吗? (4认同)
  • @Jonathan Leffler - 您将为用户定义的类型使用什么命名约定? (4认同)

mma*_*lay 46

它是用于命名数据​​类型的约定,例如typedef:


typedef struct {
  char* model;
  int year;
...
} car_t;

  • 不要对您自己的类型使用“_t”后缀,因为它们在某些标准中被保留,最好使用“_T”。另外,永远不要使用“typedef”匿名“struct”,向前声明此“struct”将变得不可能。为“struct”命名,或者根本不使用“typedef”。 (7认同)
  • 补充一下 12431...(我上面的那个人)所说的,你通常不应该使用“typedef”指针和结构/联合。这样做会令人困惑,并且只会混淆类型信息。`struct foo f;` 和 `union userinput *ui_ptr;` 比 `foo f;` 和 `userinput ui;` 更清晰、更容易理解。我知道使用简短的类型名称很诱人,但不要这样做。函数指针是 IMO 可以接受的一个例外,例如 `typedef void (*foobarfn)(struct foobar *);` ... `foobarfn my_callback = find_response(some_input);` (4认同)

Ben*_*oit 38

_t通常包装一个不透明类型的定义.

GCC只是添加_t以您可能不使用的保留命名空间结尾的名称,以避免与未来版本的Standard C和POSIX (GNU C库手册)发生冲突.经过一番研究,我终于在POSIX标准(1003.1,基本原理(资料性))中找到了正确的参考:

B.2.12数据类型

名称空间污染问题促使要求本节中定义的其他类型以''_t'结尾.很难在一个头文件中定义一个类型(其中该类型不是由IEEE Std 1003.1-2001定义的类型),而在另一个头文件中使用它而不在程序的名称空间中添加符号.为了允许实现者提供他们自己的类型,所有符合要求的应用程序都需要避免以"_t"结尾的符号,这允许实现者提供其他类型.由于类型的主要用途是结构成员的定义,它可以(并且在许多情况下必须)添加到IEEE Std 1003.1-2001中定义的结构中,因此对其他类型的需求是引人注目的.

简而言之,标准表示很有可能扩展标准类型列表,因此标准限制_t命名空间供自己使用.

例如,您的程序与POSIX 1003.1问题6匹配,并且您定义了一种类型foo_t.POSIX 1003.1问题7最终以新定义的类型发布foo_t.您的程序与新版本不匹配,这可能是一个问题.限制_t使用会阻止重构代码.因此,如果您的目标是POSIX合规性,那么您应该完全避免_t标准所说的那样.

旁注:就个人而言,我尝试坚持POSIX,因为我认为它为清洁编程提供了良好的基础知识.此外,我非常喜欢Linux编码风格(第5章)指南.为什么不使用typedef有一些很好的理由.希望这有帮助!


mkC*_*ark 18

它是数据类型的标准命名约定,通常由typedef定义.许多处理硬件寄存器的C代码使用C99定义的标准名称来表示有符号和无符号固定大小的数据类型.作为惯例,这些名称位于标准头文件(stdint.h)中,以_t结尾.


Toy*_*der 11

_t并不具有任何特殊含义.但是将_t后缀添加到typedef中已经很常见了.

您可能更熟悉变量命名的常见C实践...这类似于在前面为指针粘贴ap并在全局变量前面使用下划线(这有点不常见)的常见方法,并使用变量名i,j以及k临时循环变量.

在字大小和排序很重要的代码中,使用显式的自定义类型非常常见,例如BYTE WORD(通常是16位)DWORD(32位).

int_t是不是很好,因为int平台之间的定义各不相同 - 所以int你遵守哪些?(尽管如今,大多数以PC为中心的开发都将其视为32位,非PC开发的大部分内容仍将int视为16位).


Mat*_*tis 10

这只是一种意味着"类型"的约定.这对编译器来说没有什么特别之处.


Dou*_*yle 9

这意味着类型. size_t是尺寸类型.


Ily*_*lya 8

关于这个问题有一些很好的解释.只是为了添加另一个重新定义类型的原因:

在许多嵌入式项目中,所有类型都被重新定义,以正确地说明给定类型的大小,并提高跨不同平台(即硬件类型编译器)的可移植性.

另一个原因是使您的代码可以跨不同的操作系统移植,并避免与您在代码中集成的操作系统中的现有类型发生冲突.为此,通常添加唯一(尽可能)的前缀.

例:

typedef unsigned long dc_uint32_t;
Run Code Online (Sandbox Code Playgroud)


Gre*_*ill 7

如果您正在处理硬件接口代码,那么您正在查看的代码的作者可能已定义int_t为特定大小的整数.C标准没有为int类型指定特定大小(可能取决于您的编译器和目标平台),并且使用特定int_t类型将避免该可移植性问题.

这是硬件接口代码特别重要的考虑因素,这可能是您第一次注意到那里的约定的原因.