我查看了一些代码,发现惯例是将指针类型转换为
SomeStruct*
进入
typedef SomeStruct* pSomeStruct;
这有任何优点吗?
我查看了一些代码,发现惯例是将指针类型转换为
SomeStruct*
进入
typedef SomeStruct* pSomeStruct;
这有任何优点吗?
当指针本身可以被视为“黑匣子”即一个数据片段,其内部表示与代码无关时,这种方法是适当的。
如果您的代码从不对指针进行解引用,并且您只是通过API函数传递它(有时通过引用),那么typedef不仅可以减少代码中*
的数量,而且还建议程序员不应该真的去管指针。
这也使得将来更容易更改API,如果需要的话。例如,如果您更改使用ID而不是指针(反之亦然),现有代码不会中断,因为指针本来就不应该被解引用。
FILE*
没有被 typedef 为模糊指针的原因是为了允许像 getc()
和 putc()
这样的宏直接操作 FILE
结构体,以在大多数情况下避免函数调用开销。 - chqrlie根据我的经验,隐藏 '*
' 会使代码难以阅读。
Device
的指针,并将其 typedef
为 Device_Ptr
(而不是使用 Device *
或类似的方式),那么它就非常易读。我看到很多成熟且相当大的库都这样做。特别是在 C++ 中,如果你添加了模板,这可以减少你的打字量。 - rbaleksandarmyTypePtr
或 myTypeRef
而不是那个星号。:P - Christoffer Bubach我只有在处理函数指针时才在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"是指向一个函数的指针,该函数接受两个参数(一个"int"和一个"SigCatcher"),并返回一个"SigCatcher"。而"signal()"本身也是一个函数,它接受两个参数(一个"int"和一个"SigCatcher"),并返回一个"SigCatcher"。sig_t
与我的SigCatcher
相匹配,是的,它极大地简化了signal()
的声明。 - Jonathan Leffler这可以帮助你避免一些错误。例如在以下代码中:
int* pointer1, pointer2;
pointer2不是指向int *的指针,而只是一个简单的int。
但是,使用typedef就不会发生这种情况:
typedef int* pInt;
pInt pointer1, pointer2;
它们现在都是int *。
int *p1 = NULL, *p2 = NULL;
-> @Daniel Daranas:int *p1 = NULL,*p2 = NULL;
- Matt Joiner我的回答是明确的“不”。
为什么呢?
首先,你只是把一个单字符*
换成另一个单字符p
。这没有任何收益。仅凭这一点,就应该让你避免这样做,因为做无用的额外工作总是不好的。
其次,这是重要原因,*
携带的含义是不好隐藏的。如果我像这样将某些东西传递给一个函数
void foo(SomeType bar);
void baz() {
SomeType myBar = getSomeType();
foo(myBar);
}
我不希望通过将myBar
传递给foo()
来改变它的含义。毕竟,我是按值传递的,所以foo()
只会看到myBar
的副本,对吧?但是当SomeType
被别名指向某种指针时就不是这样了!特别是当该指针作为指向某种对象的引用时,其值基本上就是指针的含义:我不关心指针本身是否更改(由于按值传递),我只关心对象是否更改(指针背后的对象)。
这同样适用于C指针和C++智能指针:如果您向用户隐藏它们是指针的事实,您将创建完全不必要的混乱。所以,请不要给您的指针取别名。
(我认为typedef指针类型的习惯只是试图掩盖程序员拥有多少个星号的误导性尝试http://wiki.c2.com/?ThreeStarProgrammer。)
void *vp=/*...*/; foo(vp);
或 foo(0);
将没有类型保护。(用于枚举类型的typedef和用于永远不应该显示为数字的数值typedef也有类似的问题)。 - Petr SkocikmyBar
本身仍然会被复制,即使它所指向的数据没有被复制。因此,myBar
的值(一个地址)仍然不能被foo
更改,但是myBar
所指向的值可以被更改。 - Aposhianstruct _fraction
并将其指针typedef为Fraction
,则语句Fraction a = fraction(84, 2); printFrac(a); doSomething(a); printFrac(a);
可能会产生混乱的输出。使用Fraction* a = fraction(84, 2);
,就清楚了doSomething(a)
可能通过更改对象来改变a
的含义。 - cmaster - reinstate monica问题“作为指针定义的结构体大小”提出了一个有趣的侧面问题,即使用typedef来定义(结构)指针。
考虑无标签具体(而非不透明)结构类型定义:
typedef struct { int field1; double field2; } *Information;
typedef struct tag *tag;
(而且你不能在没有标签的情况下通过typedef
定义此类不透明类型)。sizeof(struct tag)
。例如,你不能有用地编写sizeof(*Information)
sizeof(Information *)
是指向指针类型的指针大小,而不是结构类型的大小。Information
的结构类型的局部变量,也没有办法创建结构类型的文件范围(全局或static
)变量,也没有办法将这样的结构(而不是指向这样的结构的指针)嵌入另一个结构或联合类型中。sizeof(*information)
。Information info = malloc(sizeof(*info));
typedef
中被隐藏的事实,这是一个好的做法——如果 info
的类型发生变化,大小分配将保持准确。但在这种情况下,这也是获取结构体大小和分配结构体的唯一方法。没有其他方式创建结构体的实例。
这取决于你的目标。
这不是不透明类型——当指针类型进行 typedef
时,必须定义结构体的详细信息。
这是一种只能与动态内存分配一起使用的类型。
这是一种无名字的类型。结构体类型的指针有一个名称,但结构体类型本身没有。
如果你想强制执行动态分配,这似乎是一种方法。
总的来说,这更可能会引起混乱和焦虑,而不是启示。
通常,使用 typedef
定义指向无标记结构体类型的指针是一个不好的做法。
NULL
强制转换为Information
并应用sizeof
来获取大小。尝试使用sizeof(*(Infomation)0)
。 - tstanisl这是一个风格问题。你会发现在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.
不要在使用const
时混淆,否则会让你的生活变得痛苦。
typedef foo *fooptr;
const fooptr bar1;
const foo *bar2
< p> `bar1` 和 `bar2` 是相同的类型吗?
是的,我只是引用Herb Sutter的Guru所说的真理。 ;)
-- 编辑 --
添加链接到引用文章。
http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835
如果这样做,您将无法创建const pSomeStruct的STL容器,因为编译器会读取:
list<const pSomeStruct> structs;
as
list<SomeStruct * const> structs;
这不是一个合法的STL容器,因为元素不可分配。
请参阅此问题。
list<const ordinary_type>
,因为它无法工作,所以也不会有任何混淆。 - user267885list<const SomeStruct*>
是完全有效的,因为const SomeStruct*
是可复制赋值的。 - Dan Hook