为什么 C 程序员使用 typedef 来重命名基本类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3340843/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:39:14  来源:igfitidea点击:

Why do C programmers use typedefs to rename basic types?

c++c

提问by Michael Louis Thaler

So I'm far from an expert on C, but something's been bugging me about code I've been reading for a long time: can someone explain to me why C(++) programmers use typedefs to rename simple types? I understand why you would use them for structs, but what exactly is the reason for declarations I see like

所以我远不是 C 方面的专家,但是我已经阅读了很长时间的代码一直困扰着我:有人可以向我解释为什么 C(++) 程序员使用 typedef 来重命名简单类型吗?我理解你为什么要将它们用于结构,但我看到的声明的原因究竟是什么

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

Is there some advantage to this that isn't clear to me (a programmer whose experience begins with Java and hasn't ventured far outside of strictly type-safe languages)? Because I can't think of any reason for it--it looks like it would just make the code less readable for people unfamiliar with the project.

这是否有一些我不清楚的优势(一个从 Java 开始并且没有涉足严格类型安全语言的程序员)?因为我想不出任何原因 - 看起来它只会使不熟悉项目的人的代码可读性降低。

Feel free to treat me like a C newbie, I honestly know very little about it and it's likely there are things I've misunderstood from the outset. ;)

随意把我当作 C 新手来对待,老实说,我对此知之甚少,而且很可能有些事情我从一开始就误解了。;)

回答by AnT

Renaming types without changing their exposed semantics/characteristics doesn't make much sense. In your example

重命名类型而不改变它们暴露的语义/特征没有多大意义。在你的例子中

typedef unsigned char uch;
typedef unsigned long ulg;

belong to that category. I don't see the point, aside from making a shorter name.

属于那个类别。除了取一个更短的名字之外,我没有看到这一点。

But these ones

但这些

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

are a completely different story. For example, s16stands for "signed 16 bit type". This type is not necessarily signed short. Which specific type will hide behind s16is platform-dependent. Programmers introduce this extra level of naming indirection to simplify the support for multiple platforms. If on some other platform signed 16 bit type happens to be signed int, the programmer will only have to change one typedef definition. UBYTEapparently stands for an unsigned machine byte type, which is not necessarily unsigned char.

是一个完全不同的故事。例如,s16代表“有符号的 16 位类型”。这种类型不一定signed short。隐藏在后面的特定类型s16取决于平台。程序员引入了这种额外的命名间接级别,以简化对多平台的支持。如果在其他某个平台上有符号的 16 位类型恰好是signed int,则程序员只需更改一个 typedef 定义。UBYTE显然代表无符号机器字节类型,不一定是unsigned char.

It's worth noting that the C99 specification already provides a standard nomenclature for integral types of specific width, like int16_t, uint32_tand so on. It probably makes more sense to stick with this standard naming convention on platforms that don't support C99.

值得注意的是,C99 规范已经为特定宽度的整数类型提供了标准命名法,例如int16_tuint32_t等等。在不支持 C99 的平台上坚持这个标准命名约定可能更有意义。

回答by sharptooth

This allows for portability. For example you need an unsigned 32-bit integer type. Which standard type is that? You don't know - it's implementation defined. That's why you typedefa separate type to be 32-bit unsigned integer and use the new type in your code. When you need to compile on another C implementation you just change the typedefs.

这允许便携性。例如,您需要一个无符号的 32 位整数类型。那是哪种标准类型?你不知道 - 它是实现定义的。这就是为什么您将typedef一个单独的类型设为 32 位无符号整数并在您的代码中使用新类型的原因。当您需要在另一个 C 实现上编译时,您只需更改typedefs.

回答by Amardeep AC9MF

Sometimes it is used to reduce an unwieldy thing like volatile unsigned longto something a little more compact such as vuint32_t.

有时它用于将笨重的东西简化为volatile unsigned long更紧凑的东西,例如vuint32_t.

Other times it is to help with portability since types like intare not always the same on each platform. By using a typedef you can set the storage class you are interested in to the platform's closest match without changing all the source code.

其他时候它有助于可移植性,因为int每个平台上的类型并不总是相同的。通过使用 typedef,您可以将您感兴趣的存储类设置为最接近平台的匹配,而无需更改所有源代码。

回答by Hyman

There are many reasons to it. What I think is:

原因有很多。我的想法是:

  1. Typename becomes shorter and thus code also smaller and more readable.
  2. Aliasing effect for longer structure names.
  3. Convention used in particular team/companies/style.
  4. Porting - Have same name across all OS and machine. Its native data-structure might be slightly different.
  1. Typename 变得更短,因此代码也更小且更具可读性。
  2. 较长结构名称的别名效应。
  3. 用于特定团队/公司/风格的约定。
  4. 移植 - 在所有操作系统和机器上具有相同的名称。它的原生数据结构可能略有不同。

回答by Andrew-Dufresne

Following is a quote from The C Programming Language (K&R)

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

Besides purely aesthetic issues, there are two main reasons for using typedefs.

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

First- to parameterize a program

首先 - 参数化程序

The first is to parameterize a program against portability problems. If typedefs are used for data types that may be machine-dependent, only the typedefs need change when the program is moved.

One common situation is to use typedef names for various integer quantities, then make an appropriate set of choices of short, int, and long for each host machine.Types like size_t and ptrdiff_t from the standard library are examples.

第一个是针对可移植性问题对程序进行参数化。如果 typedef 用于可能依赖于机器的数据类型,则在移动程序时只需要更改 typedef。

一种常见情况是对各种整数量使用 typedef 名称,然后为每台主机做出一组适当的 short、int 和 long 选择。标准库中的 size_t 和 ptrdiff_t 等类型就是示例。

The italicized portions tells us that programmers typedefbasic type for portability. If I want to make sure my program works on different platforms, using different compiler, I will try to ensure that its portability in every possible way and typedefis one of them.

斜体部分告诉我们程序员typedef的可移植性的基本类型。如果我想确保我的程序在不同的平台上工作,使用不同的编译器,我将尝试以各种可能的方式确保它的可移植性,并且typedef是其中之一。

When I started programming using Turbo C compiler on Windows platform, it gave us the size of int2. When I moved to Linux platform and GCC complier, the size I get is 4. If I had developed a program using Turbo C which relied on the assertion that sizeof( int )is always two, it would have not ported properly to my new platform.

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

Hope it helps.

希望能帮助到你。

Following quote from K&R is not related to your query but I have posted it too for the sake of completion.

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

Second- to provide better documentation

其次——提供更好的文档

The second purpose of typedefs is to provide better documentation for a program - a type called Treeptr may be easier to understand than one declared only as a pointer to a complicated structure.

typedefs 的第二个目的是为程序提供更好的文档 - 一种称为 Treeptr 的类型可能比仅声明为指向复杂结构的指针的类型更容易理解。

回答by R.. GitHub STOP HELPING ICE

Most of these patterns are bad practices that come from reading and copying existing bad code. Often they reflect misunderstandings about what C does or does not require.

大多数这些模式都是来自阅读和复制现有不良代码的不良做法。它们通常反映了对 C 需要什么或不需要什么的误解。

  1. Is akin to #define BEGIN {except it saves some typing instead of making for more.
  2. Is akin to #define FALSE 0. If your idea of "byte" is the smallest addressable unit, charis a byte by definition. If your idea of "byte" is an octet, then either charis the octet type, or your machine has no octet type.
  3. Is really ugly shorthand for people who can't touch type...
  4. Is a mistake. It should be typedef uint32_t u32;or better yet, uint32_tshould just be used directly.
  5. Is the same as 4. Replace uint32_twith int16_t.
  1. 类似于#define BEGIN {除了它节省了一些打字而不是更多的打字。
  2. 类似于#define FALSE 0. 如果您认为“字节”是最小的可寻址单位,char那么根据定义就是字节。如果您对“字节”的想法是八位字节,那么要么char是八位字节类型,要么您的机器没有八位字节类型。
  3. 对于不能触摸类型的人来说真的是丑陋的速记......
  4. 是一个错误。它应该typedef uint32_t u32;或更好,uint32_t应该直接使用。
  5. 与 4 相同。替换uint32_tint16_t

Please put a "considered harmful" stamp on them all. typedefshould be used when you really need to create a new type whose definition could change over the life cycle of your code or when the code is ported to different hardware, not because you think C would be "prettier" with different type names.

请在所有这些物品上贴上“被认为有害”的印记。typedef当您确实需要创建一个新类型的定义可能会在您的代码的生命周期中发生变化时,或者当代码被移植到不同的硬件时,应该使用它,而不是因为您认为 C 使用不同的类型名称会“更漂亮”。

回答by houman001

To cut the long story short, you might want to do that to make your code portable (with less effort/editing). This way you don't depend to 'int', instead you are using INTEGER that can be anything you want.

长话短说,您可能希望这样做以使您的代码可移植(更少的工作/编辑)。这样您就不必依赖于 'int',而是使用可以是您想要的任何东西的 INTEGER。

回答by Michael Foukarakis

All [|u]intN_ttypes, where N=8|16|32|64 and so forth, are defined per architecture in this exact manner. This is a direct consequence of the fact that the standard does not mandate that char,int,float, etc. have exactly N bits - that would be insane. Instead, the standard defines minimum and maximum values of each type as guarantees to the programmer, and in various architectures types may well exceed those boundaries. It is not an uncommon sight.

所有[|u]intN_t类型,其中 N=8|16|32|64 等等,都以这种精确的方式在每个架构中定义。这是事实的直接后果,该标准并不强制charintfloat等有确切的N位-这将是疯狂的。相反,该标准将每种类型的最小值和最大值定义为对程序员的保证,并且在各种架构中类型可能会超出这些界限。这种景象并不少见。

The typedefs in your post are used to defined types of a certain length, in a specific architecture. It's probably not the best choice of naming; u32and s16are a bit too short, in my opinion. Also, it's kind of a bad thing to expose the names ulgand uch, one could prefix them with an application specific string since they obviously will not be exposed.

typedef您帖子中的s 用于在特定架构中定义特定长度的类型。这可能不是命名的最佳选择;u32并且s16有点太短了,在我看来。此外,公开名称ulg和是一件坏事uch,可以用应用程序特定的字符串作为前缀,因为它们显然不会公开。

Hope this helps.

希望这可以帮助。

回答by Praveen S

We use it to make it Project/platform specific, everything has a common naming convention

我们使用它来使其特定于项目/平台,一切都有一个通用的命名约定

pname_int32, pname_uint32, pname_uint8-- pname is project/platform/module name

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

And some #defines

还有一些#defines

pname_malloc, pname_strlen

It easier to read and shortens long datatypes like unsigned char to pname_uint8 also making it a convention across all modules.

更容易阅读并将像 unsigned char 这样的长数据类型缩短为 pname_uint8 也使其成为所有模块的约定。

When porting you need to just modify the single file , thus making porting easy.

移植时只需修改单个文件,从而使移植变得容易。