typedef指针是个好主意吗?
我查看了一些代码,并注意到惯例是转向types指针types
SomeStruct*
成
typedef SomeStruct* pSomeStruct;
这有什么好处吗?
当指针本身可以被看作是一个“黑盒子”,也就是说,一个内部表示应该与代码无关的数据的时候,这可能是合适的。
从本质上讲,如果你的代码永远不会取消指针的引用,而只是将它传递给API函数(有时是通过引用),那么typedef不仅可以减less代码中的*
s数量,还可以向程序员build议指针不应该被干涉。
这也使得在需要的时候更容易改变API,例如使用ID而不是指针(反之亦然)。 由于指针从来不应该被解除引用,现有的代码不会被破坏。
不是以我的经验。 隐藏“ *
”会使代码难以阅读。
我唯一一次在typedef中使用指针的时候是处理指向函数的指针的时候:
typedef void (*SigCatcher(int, void (*)(int)))(int);
typedef void (*SigCatcher)(int); SigCatcher old = signal(SIGINT, SIG_IGN);
否则,我觉得他们更困惑,而不是帮助。
被触发的声明是指向signal()
函数的指针的正确types,而不是信号捕捉器的指针。 可以通过编写更清楚(使用上面修正的SigCatcher
types):
typedef SigCatcher (*SignalFunction)(int, SigCatcher);
或者,声明signal()
函数:
extern SigCatcher signal(int, SigCatcher);
也就是说, SignalFunction
是一个函数指针,它接受两个参数(一个int
和一个SigCatcher
)并返回一个SigCatcher
。 signal()
本身是一个函数,它接受两个参数(一个int
和一个SigCatcher
)并返回一个SigCatcher
。
这可以帮助您避免一些错误。 例如在以下代码中:
int* pointer1, pointer2;
pointer2不是一个int * ,它是简单的int 。 但是用typedefs这不会发生:
typedef int* pInt; pInt pointer1, pointer2;
他们现在都是int * 。
这是一个风格问题。 您在Windows头文件中经常看到这种代码。 虽然他们倾向于使用全部大写的版本,而不是使用小写字母p作为前缀。
我个人避免使用typedef。 让用户明确地说他们想要一个Foo *而不是PFoo就更加清楚了。 Typedef是最适合这些天使STL可读:)
typedef stl::map<stl::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;
它(像这么多的答案)取决于。
在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.
Typedef用于使代码更具可读性,但是将指针作为typedef会增加混淆。 最好避免typedef指针。
如果你这样做,你将无法创buildconst pSomeStruct的STL容器,因为编译器读取:
list<const pSomeStruct> structs;
如
list<SomeStruct * const> structs;
由于元素不可分配,这不是合法的STL容器。
看到这个问题 。
讨论的假设感兴趣的语言是C. C ++的后果尚未考虑。
对一个未标记的结构使用一个指针typedef
问题被定义为指针的struct的大小引发了一个有趣的关于使用typedef
(结构)指针的侧面。
考虑无标记的具体(不透明)结构types定义:
typedef struct { int field1; double field2; } *Information;
成员的细节完全与这个讨论相关; 所有重要的是,这不是一个不透明的types,如typedef struct tag *tag;
(你不能通过没有标签的typedef
来定义这种不透明的types)。
提出的问题是“你怎么能find那个结构的大小”?
简短的答案是“只能通过一个types的variables”。 没有标签用于sizeof(struct tag)
。 例如,您不能有用地写 ,而sizeof(*Information)
sizeof(Information *)
是指向指针types的指针的大小,而不是结构types的大小。
事实上,如果你想分配这样的结构,除了通过dynamic分配(或者模仿dynamic分配的代理技术)之外,你不能创build一个结构。 没有办法创build一个结构types的局部variables,其指针被称为Information
,也没有办法创build结构types的文件范围(全局或static
)variables,也没有办法embedded这样的结构(而不是指向这种结构的指针)转换为另一种结构或联合types。
你可以 – 必须 – 写:
Information info = malloc(sizeof(*info));
除了指针隐藏在typedef
这个事实之外,这是一个好习惯 – 如果info
types改变,大小分配将保持准确。 但在这种情况下,这也是获得结构规模和分配结构的唯一途径。 而且没有其他方法可以创build结构的实例。
这有害吗?
这取决于你的目标。
这不是一个不透明的types – 当指针types是typedef
时,必须定义结构的细节。
这是一种只能用于dynamic内存分配的types。
这是一种无名的types。 指向结构types的指针有一个名字,但是结构types本身没有。
如果你想强制dynamic分配,这似乎是一个办法。
但总的来说,比开悟更容易造成混乱和焦虑。
概要
一般来说,使用typedef
来定义指向无标记结构types的指针是一个糟糕的主意。
Win32 API用几乎每个结构(如果不是全部的话)
POINT => *LPPOINT WNDCLASSEX => *LPWNDCLASSEX RECT => *LPRECT PRINT_INFO_2 => *LPPRINT_INFO_2
它是如此一致,但在我看来,它不会增加任何优雅。
我的回答是明确的“否”。
为什么?
那么,首先,你只需要交换一个字符*
为另一个字符p
。 这是零收益。 单靠这一点,你就不应该这样做,因为做一些毫无意义的事情总是不好的。
其次,那就是重要的原因, *
带有不好隐藏的意思 。 如果我把一些东西传递给这样的函数
void foo(SomeType bar); void baz() { SomeType myBar = getSomeType(); foo(myBar); }
我不希望myBar
的含义通过传递给foo()
来改变。 毕竟,我正在传递价值,所以foo()
只能看到myBar
的副本吗? 不是当SomeType
别名意味着某种指针!
这适用于C指针和C ++智能指针:如果你隐瞒了指向你的用户的事实,你将会产生混淆,这是完全不必要的。 所以,请不要混淆你的指针。
(我相信typedefing指针types的习惯只是一个误导性的尝试,以隐藏程序员http://wiki.c2.com/?ThreeStarProgrammer中有多less个星星。);
前一段时间,我对这个问题回答“不”。 现在,随着智能指针的兴起,指针不再总是以星号“*”来定义。 所以没有什么明显的types是一个指针与否。
所以现在我会说:typedef指针是很好的,只要它是非常清楚的,它是一个“指针types”。 这意味着你必须专门为它使用前缀/后缀。 不,“p”不是一个足够的前缀,例如。 我可能会去“ptr”。
使用typedef的目的是隐藏实现细节,但是typedef-指针属性隐藏太多,使得代码难以阅读/理解。 所以请不要这样做。
如果你想隐藏实现细节(这通常是一件好事),不要隐藏指针部分。 以标准FILE
界面的原型为例:
FILE *fopen(const char *filename, const char *mode); char *fgets(char *s, int size, FILE *stream);
这里fopen返回一个指向某个结构FILE
(你不知道实现细节)的指针 。 也许FILE
不是一个很好的例子,因为在这种情况下,它可以使用一些隐藏事实的pFILEtypes的指针。
pFILE fopen(const char *filename, const char *mode); char *fgets(char *s, int size, pFILE stream);
但是,这只会起作用,因为你不会直接指向内容。 当你键入一些指针,你有些地方修改代码变得很难阅读我的经验。