输入deff指针是个好主意吗?

时间:2009-04-15 03:14:19

标签: c++ c pointers typedef conventions

我查看了一些代码并发现惯例是将指针类型转换为

SomeStruct* 

typedef SomeStruct* pSomeStruct;

这有什么好处吗?

14 个答案:

答案 0 :(得分:96)

当指针本身可以被视为“黑匣子”时,这是合适的,也就是说,其内部表示应与代码无关的一段数据。

基本上,如果你的代码从不取消引用指针,并且只是将它传递给API函数(有时通过引用),那么typedef不仅会减少*的数量在您的代码中,但也向程序员建议指针不应该真正被插入。

如果需要,这也可以在将来更容易地更改API。例如,如果您更改为使用ID而不是指针(反之亦然),现有代码将不会中断,因为指针永远不应该首先被解除引用。

答案 1 :(得分:69)

不符合我的经验。隐藏“*”会使代码难以阅读。

答案 2 :(得分:28)

我在typedef中使用指针的唯一一次是处理指向函数的指针时:

typedef void (*SigCatcher(int, void (*)(int)))(int);

typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);

否则,我发现它们更有说服力而不是帮助。

<小时/> 被删除的声明是指向signal()函数的指针的正确类型,而不是信号捕获器的指针。通过编写:

,可以使其更清晰(使用上面更正的SigCatcher类型)
 typedef SigCatcher (*SignalFunction)(int, SigCatcher);

或者,声明signal()函数:

 extern SigCatcher signal(int, SigCatcher);

也就是说,SignalFunction是一个指向函数的指针,该函数接受两个参数(intSigCatcher)并返回{{1 }}。 SigCatcher本身是一个函数,它接受两个参数(signal()int)并返回SigCatcher

答案 3 :(得分:14)

这可以帮助您避免一些错误。例如,在以下代码中:

int* pointer1, pointer2;

指针2不是 int * ,它是简单的 int 。 但是对于typedef,这不会发生:

typedef int* pInt;
pInt pointer1, pointer2;

他们现在都是 int *

答案 4 :(得分:11)

我的回答很清楚,没有&#34;。

为什么?

首先,您只需将一个字符*换成另一个字符p即可。那是增益。仅此一点就不会让你这样做,因为做一些毫无意义的额外事情总是很糟糕。

其次,这是重要的原因, *带有隐藏不好的含义。如果我将某些东西传递给像这样的函数

void foo(SomeType bar);

void baz() {
    SomeType myBar = getSomeType();
    foo(myBar);
}

我不希望通过将myBar传递给foo()来改变foo()的含义。毕竟,我是按价值传递的,因此myBar只能看到SomeType的副本吗?当(?:[^\#\\S\\+]*)别名为某种指针时,不是这样!

这适用于C指针和C ++智能指针:如果隐藏它们是指向用户的指针这一事实,您将产生完全不必要的混淆。所以,请不要把你的指针作别名。

(我相信typedefing指针类型的习惯只是误导了一个程序员http://wiki.c2.com/?ThreeStarProgrammer隐藏了多少个星星。)

答案 5 :(得分:5)

这是一种风格问题。您在Windows头文件中经常看到这种代码。虽然他们倾向于选择全部大写版本,而不是使用小写p作为前缀。

我个人避免使用typedef。让用户明确表示他们想要一个Foo *比PFoo更清楚。 Typedef最适合使STL可读:)

typedef stl::map<stl::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;

答案 6 :(得分:5)

它(就像许多答案一样)取决于。

在C中,这是非常常见的,因为你试图伪装一个对象是一个指针。你试图暗示这是你所有函数操作的对象(我们知道它是一个指针,但它代表你正在操作的对象)。

MYDB   db = MYDBcreateDB("Plop://djdjdjjdjd");

MYDBDoSomthingWithDB(db,5,6,7);
CallLocalFuc(db); // if db is not a pointer things could be complicated.
MYDBdestroyDB(db);

MYDB下面可能是某个对象的指针。

在C ++中不再需要这个 主要是因为我们可以通过引用传递内容,并将方法合并到类声明中。

MyDB   db("Plop://djdjdjjdjd");

db.DoSomthingWithDB(5,6,7);
CallLocalFuc(db);   // This time we can call be reference.
db.destroyDB();     // Or let the destructor handle it.

答案 7 :(得分:4)

Typedef用于使代码更具可读性,但将指针作为typedef会增加混淆。最好避免使用typedef指针。

答案 8 :(得分:4)

在假设感兴趣的语言是C的情况下进行讨论。尚未考虑C ++的分歧。

使用指针typedef表示未标记结构

问题Size of a struct that is defined as a pointer为使用typedef(结构)指针提出了一个有趣的侧面。

考虑无标记混凝土(非透明)结构类型定义:

typedef struct { int field1; double field2; } *Information;

成员的详细信息与此讨论完全相同;重要的是,这不是像typedef struct tag *tag;那样的不透明类型(并且你不能通过没有标签的typedef定义这种不透明类型。)

提出的问题是“你怎么能找到那个结构的大小”?

简短回答是“只能通过类型变量”。没有标记可用于sizeof(struct tag)。例如,您无法有用地编写 sizeof(*Information) sizeof(Information *)是指向指针类型的指针的大小,而不是结构类型的大小。

实际上,如果要分配这样的结构,除了通过动态分配(或模仿动态分配的代理技术)之外,您不能创建一个结构。无法创建结构类型的局部变量,其指针名为Information,也没有办法创建结构类型的文件范围(全局或static)变量,也不是有一种方法可以将这样的结构(与指向这种结构的指针相对)嵌入到另一个结构或联合类型中。

你可以 - 必须 - 写:

Information info = malloc(sizeof(*info));

除了指针隐藏在typedef中之外,这是一种很好的做法 - 如果info的类型发生变化,则大小分配将保持准确。但在这种情况下,它也是获得结构大小和分配结构的唯一方法。并且没有其他方法可以创建结构的实例。

这有害吗?

这取决于你的目标。

这不是一个不透明的类型 - 当指针类型为typedef时,必须定义结构的细节。

这种类型只能用于动态内存分配。

这是一种无名的类型。指向结构类型的指针有一个名称,但结构类型本身没有。

如果你想强制执行动态分配,这似乎是一种方法。

但总的来说,它比起启发更容易引起混乱和焦虑。

摘要

一般来说,使用typedef定义指向无标记结构类型的指针是一个坏主意。

答案 9 :(得分:3)

如果这样做,您将无法创建const pSomeStruct的STL容器,因为编译器会读取:

list<const pSomeStruct> structs;

作为

list<SomeStruct * const> structs;

这不是合法的STL容器,因为元素不可分配。

请参阅此 question

答案 10 :(得分:2)

否。

一旦将其与class MaintenanceAgreement extends Agreement { String level Map category = [:] //p1 to p5 and sla details //static belongsTo = [serviceProvider : OrgRoleInstance, maintainer: OrgRoleInstance] // implemented as unidirectional many to one ! mag point to org static belongsTo = [maintainer: OrgRoleInstance] static constraints = { level nullable:false //serviceProvider nullable:true maintainer nullable:false //ref to maintainer party category nullable:false } } 混合在一起,它将使您的生活痛苦不堪。

const

typedef foo *fooptr; const fooptr bar1; const foo *bar2 bar1是同一类型吗?

是的,我只是引用赫伯·萨特的上师。她说了很多实话。 ;)

-编辑-

添加引用文章的链接。

http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835

答案 11 :(得分:1)

Win32 API对几乎所有结构(如果不是全部)

执行此操作
POINT => *LPPOINT
WNDCLASSEX => *LPWNDCLASSEX
RECT => *LPRECT
PRINT_INFO_2 => *LPPRINT_INFO_2

它是如何一致的很好,但在我看来它并没有增添任何优雅。

答案 12 :(得分:1)

typedef的目的是隐藏实现细节,但是类型定义指针属性会隐藏太多并使代码更难以阅读/理解。 所以请不要这样做。


如果要隐藏实现细节(这通常是一件好事),请不要隐藏指针部分。以标准FILE接口的原型为例:

FILE *fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, FILE *stream);

这里fopen将指针返回到某个结构FILE(您不知道其实现细节)。也许FILE不是一个很好的例子,因为在这种情况下它可以使用一些pFILE类型来隐藏它是一个指针。

pFILE fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, pFILE stream);

然而,这只会起作用,因为你永远不会搞砸直接指向的内容。根据我的经验,当你输入某些指针时,某些地方会修改代码变得非常难以阅读。

答案 13 :(得分:0)

前段时间,我对这个问题回答“否”。现在,随着智能指针的兴起,指针不再总是用'*'定义。所以没有什么明显的类型是指针或不是。

所以现在我要说:只要非常清楚它是一个“指针类型”,就可以输入指定指针。这意味着您必须专门为它使用前缀/后缀。不,例如,“p”不是足够的前缀。我可能会选择“ptr”。