定义指针类型的typedef

4
我在 Stack Overflow 上阅读了一些问题,其中涉及到为什么 typedef 指针类型是不好的。以下是这些问题:
不透明的C结构:应如何声明?常量正确性和不可变分配对象
我想知道是否有人能够扩展和解释为什么 typedef 指针类型是不好的,并可能提供一些错误可能发生的示例。
另外,如果 typedef 指针类型确实是不好的,那么为什么 Win32 API 还要这样做呢?在 Win32 中,HANDLE(以及有效的 Handle 类型)被定义为 void * 的 typedef。

2
https://dev59.com/7nRB5IYBdhLWcg3wAjNH - chrisaycock
@chrisaycock 不错的链接,谢谢。 - jay.lee
8个回答

11
Johannes已经指出,对指针进行typedef并不是本质上的坏事,我也同意。
以下是基于我的主观看法,关于清晰度和可维护性的一些指导方针:
- 通常情况下,应该函数指针类型进行typedef。 原因:
函数指针的声明可能会变得非常混乱和难以阅读。 - 通常情况下,不要对原始对象指针进行typedef,除非指针类型是一个抽象的概念(例如,当你只需要一个“指向T的指针”时)。 原因1:
使用Foo*Foo const*比使用FooPtr更清晰。通过名称,你必须查找名称以查看它被定义为什么。也许它是某个智能指针,也许它是指向const的指针,无论如何,这个名称使你不必要地在其他地方查找。 原因2:
有些程序员会对consttypedef的指针类型的组合感到困惑。例如,在Microsoft代码中,我经常看到类似于FooPtr const的东西,其中程序员显然认为它意味着Foo const*。但实际上不是这样,它意味着Foo* const。 - 通常情况下,当指针类型是一个抽象概念时,应该也对原始对象指针进行typedef,即指针类型在未来可以被某些其他类型替换的指针类型,例如HANDLE。 原因:
与使用命名常量相同:如果没有适当的名称,搜索和替换可能会更改意思不同的出现,并且可能无法更改未以精确“正确”方式表达的出现。
然而,与几乎所有类型的样式一样,支持和反对的论点都相当薄弱,因此最终的选择取决于个人偏好、编码标准、同事的意见等等。
如果有自由选择,以上通常是我会选择的。但在特殊情况下,我已经偏离了这些指导方针/规则。就像优秀的艺术品一样,优秀的代码是由那些足够了解规则的人创造出来的,他们也知道何时打破规则...
祝好运!

6

将指针类型定义为typedef并不是客观上不好的。许多优秀的代码使用它来typedef指向处理函数类型的指针,这在类似于“HANDLER”的情况下也很常见。

可能是某人的个人观点认为这样做不好,但这绝对不是被广泛接受的观点。我个人完全不同意那个观点。我自己很少使用该选项,但我仍然不认为它是“不好的”。


2

如果您打算在您的库的公共接口中提供一个句柄类型,请使用typedef。不要将其公开为struct foo*。句柄是指针还是其他类型完全是实现细节...它将始终像指针一样运行,但通常更方便使用某些内部数据结构的索引。


如果您喜欢编写传统风格的代码,而不是线程安全的代码,或者必须练习锁定代码而不是锁定数据,那么在内部结构中索引可能很方便。否则... - R.. GitHub STOP HELPING ICE
@R:什么?在多线程场景下,池化分配器通常具有更好的扩展性,而使用数组/池可以更好地控制虚假共享,而不是让系统分配器将数据放置在这里、那里和任何地方。你可能会感兴趣的是,在Windows下,某些类型的句柄实际上是索引,显然在Linux下是文件描述符和进程ID也是索引。我认为有大量证据支持将索引作为句柄的可行实现。 - Ben Voigt
虽然我提出的问题是在更广泛的意义上,但这个答案更与我所考虑的特定实现相关(一个不透明类型,只能通过库调用进行分配、使用和释放)。 - jay.lee

1

Windows和POSIX都有typedef指针,但这并不意味着它总是好的实践。它主要是为了隐藏实现细节,但这并不总是好事。


1
通过“typedef”指针,您实际上是遵循C的做法而不是C ++的做法。在C中,为了隐藏实现细节,通常使用typedef,因为它允许一定程度的基本数据隐藏:
typedef struct somestruct* pointer;

void foo(pointer p);

如果后来更改为

typedef struct someotherstruct* pointer; 

void foo(pointer p);

您不必更改所有使用指向“struct someotherstruct *”的指针的函数参数,甚至可以通过在someotherstruct中添加新字段来伪造多态性。

在C++中,有其他更好的方法来实现上述功能。

编辑:也许数据隐藏在这里是一个过于强烈的词,但如果正确执行,它允许您更改使用指针的指针的实现而不会破坏现有代码。


0

如果不清楚什么是指针,可能会出现内存问题。Windows将typedefs HANDLE作为void *,因为它们提供了获取和清理句柄的方法。这并不是一件坏事,但如果有很多人在项目上工作,我建议不要这样做。这主要是一个清晰度问题。


0

使用指针typedef没有问题,但需要记住,typedef并不定义新类型(像类一样),而是为现有类型定义别名。这意味着,如果您有两个typedef是同一类型的别名,您不能依赖C++的类型检查来防止您无意中混淆它们。


现在你有类型检查了:typedef struct random_garbage_dhfslkjdkljdss *my_handle_type; - R.. GitHub STOP HELPING ICE
不是很确切,但如果你将指针放在结构体内部,它会给你类型检查。 - Ferruccio

0
有时候你需要提前声明一个结构体指针,以便于函数声明的编译。你不能只是提前声明结构体本身。
typedef struct my_struct * my_struct_ptr;

extern void my_func( my_struct_ptr pointer );

typedef struct _my_struct { int a_field; } my_struct;

(使用 st20cc 3.63)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接