为什么要在C语言中这么频繁地对结构进行typedef?

 ̄綄美尐妖づ 提交于 2020-02-26 06:24:16

我看过很多程序,其中包括以下结构

typedef struct 
{
    int i;
    char k;
} elem;

elem user;

为什么经常需要它? 有任何特定原因或适用范围?


#1楼

Linux内核编码样式第5章给出了使用typedef优缺点(主要是缺点)。

请不要使用“ vps_t”之类的东西。

对结构和指针使用typedef是错误的 。 当你看到一个

vps_t a;

在源代码中是什么意思?

相反,如果说

struct virtual_container *a;

您实际上可以说出“ a”是什么。

许多人认为typedef是“帮助可读性”。 不是这样 它们仅对以下有用:

(a)完全不透明的对象(使用typedef主动隐藏该对象是什么)。

例如:“ pte_t”等不透明对象,您只能使用适当的访问器函数来访问。

注意! 不透明和“访问器功能”本身不好。 之所以将它们用于pte_t等之类,是因为那里确实存在绝对零的可访问信息。

(b)清除整数类型,其中抽象有助于避免混淆,无论是“ int”还是“ long”。

u8 / u16 / u32是完美的typedef,尽管它们比这里更适合(d)类。

注意! 再次-需要有一个原因 。 如果某事是“无符号的长”,则没有理由这样做

typedef unsigned long myflags_t;

但是,如果有明确的原因说明为什么在某些情况下它可能是“ unsigned int”而在其他配置下可能是“ unsigned long”,则一定要继续使用typedef。

(c)当您使用稀疏从字面上创建用于类型检查的类型时。

(d)在某些特殊情况下,与标准C99类型相同的新类型。

尽管眼睛和大脑只需要很短的时间就习惯了'uint32_t'这样的标准类型,但是仍然有人反对使用它们。

因此,允许使用特定于Linux的'u8 / u16 / u32 / u64'类型及其与标准类型相同的带符号等效项-尽管在您自己的新代码中不是强制性的。

编辑已使用一种或另一组类型的现有代码时,应遵循该代码中的现有选择。

(e)在用户空间中可以安全使用的类型。

在用户空间可见的某些结构中,我们不能要求C99类型,也不能使用上面的“ u32”形式。 因此,我们在与用户空间共享的所有结构中使用__u32和类似类型。

也许还有其他情况,但是该规则基本上应该是从不使用typedef,除非您可以清楚地匹配这些规则之一。

通常,指针或具有可以合理地直接访问的元素的结构永远都不应该是typedef。


#2楼

事实证明,这是有利有弊的。 有用的信息来源是开创性的书“ Expert C Programming”( 第3章 )。 简而言之,在C中,您具有多个名称空间: 标签,类型,成员名称和标识符typedef为类型引入别名,并将其定位在标记名称空间中。 即

typedef struct Tag{
...members...
}Type;

定义了两件事。 标签名称空间中的一个标签,类型名称空间中的一个类型。 所以,你都可以做Type myTypestruct Tag myTagType 。 诸如struct Type myType Tag myTagTypeTag myTagType是非法的。 另外,在这样的声明中:

typedef Type *Type_ptr;

我们定义一个指向类型的指针。 因此,如果我们声明:

Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;

然后var1var2myTagType1是指向Type的指针,而myTagType2不是。

在上面提到的书中,提到类型定义结构不是很有用,因为它仅使程序员不必编写struct这个词。 但是,与许多其他C程序员一样,我也有反对意见。 虽然有时要混淆一些名称(这就是为什么在诸如内核之类的大型代码库中不建议使用它的原因),但是当您要在C中实现多态时,它可以在此处帮助查找详细信息 。 例:

typedef struct MyWriter_t{
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
}MyWriter;

你可以做:

void my_writer_func(MyPipe *s)
{
    MyWriter *self = (MyWriter *) s;
    uint32_t myFlags = self->flags;
...
}

因此,您可以通过强制转换通过内部结构( MyPipe )访问外部成员( flags )。 对我来说, (struct MyWriter_ *) s;整个类型比做(struct MyWriter_ *) s;容易混淆(struct MyWriter_ *) s; 每次您想要执行此类功能时。 在这些情况下,简短引用是一件很重要的事情,特别是如果您在代码中大量使用该技术的话。

最后,随着最后一个方面typedef ED类型是无法扩展它们,而相比之下,宏。 例如,如果您有:

#define X char[10] or
typedef char Y[10]

然后您可以声明

unsigned X x; but not
unsigned Y y;

我们并不真正在意此结构,因为它不适用于存储说明符( volatileconst )。


#3楼

完全,在C语言中,struct / union / enum是由C语言预处理器处理的宏指令(不要误以为处理“ #include”和其他的预处理器)

所以:

struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};

struct b被扩展为如下形式:

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}

因此,在编译时,它在堆栈上的演变如下:b:int ai int i int j

这也是为什么很难拥有自引用结构的原因,C预处理程序在无法终止的声明循环中进行处理。

typedef是类型说明符,这意味着只有C编译器对其进行处理,并且可以像他想要的那样优化汇编程序代码实现。 它也不会像préprocessor那样愚蠢地使用par类型的成员来处理结构,而是使用更复杂的引用构造算法,因此构造如下:

typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;

被允许并且功能齐全。 当执行线程离开初始化函数的应用程序字段时,此实现还可以访问编译器类型转换并消除一些错误影响。

这意味着在C中,typedef更像C ++类,而不是孤独的结构。


#4楼

使用typedef可以避免每次声明该类型的变量时都必须编写struct

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct

#5楼

正如Greg Hewgill所说,typedef意味着您不再需要到处编写struct 。 这不仅可以节省击键次数,而且还可以使代码更整洁,因为它提供了更多的smidgen抽象。

像东西

typedef struct {
  int x, y;
} Point;

Point point_new(int x, int y)
{
  Point a;
  a.x = x;
  a.y = y;
  return a;
}

当您不需要在所有地方都看到“ struct”关键字时,它会变得更加干净,看起来好像您的语言中确实存在一个名为“ Point”的类型。 在typedef ,我猜是这样。

还要注意,尽管您的示例(和我的示例)省略了对struct本身的命名,但实际上,为要提供不透明的类型命名也很有用。 然后,您将在标题中包含以下代码,例如:

typedef struct Point Point;

Point * point_new(int x, int y);

然后在实现文件中提供struct定义:

struct Point
{
  int x, y;
};

Point * point_new(int x, int y)
{
  Point *p;
  if((p = malloc(sizeof *p)) != NULL)
  {
    p->x = x;
    p->y = y;
  }
  return p;
}

在后一种情况下,您无法返回“按值”,因为头文件的用户不知道其定义。 例如,这是GTK +中广泛使用的技术。

UPDATE请注意,在一些C项目中,使用typedef隐藏struct被认为是一个坏主意,Linux内核可能是最著名的此类项目。 有关Linus的愤怒话,请参阅Linux Kernel CodingStyle文档的第5章。 :)我的意思是,毕竟问题中的“应该”可能不是一成不变的。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!