为什么C程序员使用typedefs来重命名基本types?

所以我远不是C的专家,但是我一直在阅读很长时间的代码:有人可以向我解释为什么C(++)程序员使用typedefs来重命名简单types吗? 我明白你为什么要把它们用于结构,但是我所看到的声明究竟是什么原因

typedef unsigned char uch; typedef uch UBYTE; typedef unsigned long ulg; typedef unsigned int u32; typedef signed short s16; 

这对我来说有没有什么好处(一个程序员的经验是从Java开始的,而且没有在严格的types安全的语言之外冒险)? 因为我想不出任何理由 – 它看起来会让代码对于不熟悉项目的人来说不那么可读。

随意把我当作一个C新手来对待,我真的对此知之甚less,很可能从一开始就误解了一些事情。 ;)

重命名types而不改变其暴露的语义/特性没有多大意义。 在你的例子中

 typedef unsigned char uch; typedef unsigned long ulg; 

属于那个类别。 除了缩短名字之外,我看不出这一点。

但是这些

 typedef uch UBYTE; typedef unsigned int u32; typedef signed short s16; 

是一个完全不同的故事。 例如, s16代表“有符号16位types”。 这种types不一定是signed short 。 哪个特定的types会隐藏在s16 ,取决于平台。 程序员引入了额外级别的间接命名来简化对多个平台的支持。 如果在其他某个平台上签名的16位types碰巧是signed int ,程序员只需要改变一个typedef定义。 UBYTE显然代表一个无符号的机器字节types,它不一定是unsigned char

值得注意的是,C99规范已经为特定宽度的整数types提供了一个标准的术语,比如int16_tuint32_t等等。 在不支持C99的平台上使用这个标准的命名约定可能更有意义。

这允许便携性。 例如,你需要一个无符号的32位整数types。 那是哪种标准的? 你不知道 – 这是实现定义。 这就是为什么你键入一个单独的types为32位无符号整数,并在你的代码中使用新的types。 当你需要编译另一个C实现时,你只需要改变typedef

有时候它被用来减less一些笨重的东西,比如vuint32_t

其他时候则是为了便于携带,因为像int这样的types在每个平台上并不总是相同的。 通过使用typedef,您可以将您感兴趣的存储类别设置为与平台最接近的匹配,而无需更改所有源代码。

以下是C编程语言(K&R)

除了纯粹的美学问题,使用typedef有两个主要原因。

首先 – 参数化一个程序

首先是针对可移植性问题参数化一个程序。 如果typedef用于可能依赖于机器的数据types,那么当程序移动时,只有typedef需要改变。

一种常见的情况是使用不同整数量的typedef名称,然后为每个主机机器selectshort,int和long。 类似标准库中的size_t和ptrdiff_t是例子。

斜体部分告诉我们程序员input可移植性的基本types。 如果我想确保我的程序在不同的平台上工作,使用不同的编译器,我将尽力确保其可移植性和typedef是其中之一。

当我在Windows平台上使用Turbo C编译器开始编程时,它给了我们int 2的大小。当我移动到Linux平台和GCC编译器时,我得到的大小是4.如果我使用Turbo C开发了一个依赖于断言sizeof( int )总是两个,它将不能正确地移植到我的新平台。

希望能帮助到你。

以下引用来自K&R与您的查询无关,但为了完成,我也发布了它。

其次 – 提供更好的文档

typedefs的第二个目的是为一个程序提供更好的文档 – 一个名为Treeptr的types可能比只被声明为指向复杂结构的指针更容易理解。

这些模式中的大多数都是来自读取和复制现有错误代码的不良做法。 他们经常反映出对C所做或者不需要的误解。

  1. 类似于#define BEGIN {除了节省了一些打字,而不是更多。
  2. 类似于#define FALSE 0 。 如果你的想法是“字节”是最小的可寻址单元, char是一个按字节定义的字节。 如果你的想法是“字节”是八位字节,那么任何char都是八位字节types,或者你的机器没有八位字节types。
  3. 对于那些不能碰触types的人来说,简直就是丑陋的速记…
  4. 是一个错误。 它应该是typedef uint32_t u32; 或者更好, uint32_t应该直接使用。
  5. 与4相同。用int16_treplaceuint32_t

请在他们身上贴上“ 有害的 ”邮票。 当你确实需要创build一个新的types时,可以使用typedef ,这个types的定义可以在你的代码的生命周期中改变,或者代码被移植到不同的硬件上,而不是因为你认为C会使用不同的types名称更“漂亮”。

这有很多原因。 我认为是:

  1. Typename变得更短,因此代码也更小,更具可读性。
  2. 别名效果较长的结构。
  3. 公约特别用于团队/公司/风格。
  4. 移植 – 在所有操作系统和机器上都有相同的名称。 其原生数据结构可能稍有不同。

我们用它来使它成为Project / platform特定的,一切都有一个共同的命名约定

pname_int32, pname_uint32, pname_uint8 – pname是项目/平台/模块名称

还有一些#defines

 pname_malloc, pname_strlen 

它更容易读取和缩短像unsigned char pname_uint8这样的长数据types,也使其成为所有模块的约定。

当移植你需要修改单个文件,从而使移植变得容易。

长话短说,你可能想要做到这一点,使您的代码可移植(更less的努力/编辑)。 这样你就不依赖于'int',而是使用INTEGER,它可以是任何你想要的。

所有的[|u]intN_ttypes,其中N = 8 | 16 | 32 | 64等都是以这种确切的方式在每个架构中定义的。 这是标准没有要求charintfloat等具有N位的事实的一个直接结果 – 这将是疯狂的。 相反,该标准定义了每种types的最小值和最大值作为程序员的保证,在不同的体系结构中,types可能会超过这些边界。 这并不罕见。

您的文章中的typedef用于在特定体系结构中定义特定长度的types。 这可能不是命名的最佳select; 在我看来, u32s16有点太短了。 另外,暴露ulguch这个名字是不好的,可以用特定于应用程序的string作为前缀,因为它们显然不会被公开。

希望这可以帮助。

基本types的Typedef: –

  • Typedefs可以让你的代码更清晰

拥有types的目的之一是确保variables始终以打算使用的方式使用。 C和C ++提供了几种基于数据底层表示的内置types。 有时候这是够好的; 但是当您正在努力节省内存或执行需要正确精确度的数值计算时,您希望对这些问题进行严格的控制。 这个约束是为不同的types创build“包装器”类。 这可以让您的编译器发现不正确的分配,并阻止您进行分配。

 error_t get_data( char *data ); 

其中error_t的types如下所示:

 unsigned int error_t; 
  • Typedefs可以使你的代码更容易修改

Typedef提供了一个远离实际使用的types的抽象级别,让程序员可以更多地关注variables的含义。 这使得编写干净的代码变得更容易,但是它也使修改代码变得容易得多。 例如:如果您决定确实需要支持太大而无法存储在unsigned int中的大小,则可以在代码中的一个地方进行更改(typedef本身),以使size_t等同于(例如)无符号长。 几乎没有你的代码将需要改变!

有些人反对广泛使用typedef。 大部分的争论集中在这样的想法,即typedefs只是隐藏了一个variables的实际数据types。 例如,Linux内核黑客和logging员Greg Kroah-Hartman不鼓励将其用于除函数原型声明之外的任何其他用途。 他认为,这种做法不仅不必要地混淆了代码,还可能导致程序员不小心滥用那些认为它们是简单types的大型结构。

其他人则认为使用typedefs可以使代码更容易维护。 K&R指出使用typedef有两个原因。 首先,它提供了使程序更加便携的手段。 整个程序的源文件中不需要改变types,只需要改变一个typedef语句。 其次,typedef可以使像指针,结构,函数指针等复杂的声明更容易理解。

希望这会帮助你。