typedef 指针是个好主意吗?

发布于 2024-07-18 04:00:21 字数 156 浏览 10 评论 0原文

我查看了一些代码,发现约定是将指针类型转换

SomeStruct* 

为这样,

typedef SomeStruct* pSomeStruct;

这有什么优点吗?

I looked through some code and noticed that the convention was to turn pointer types like

SomeStruct* 

into

typedef SomeStruct* pSomeStruct;

Is there any merit to this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

奢华的一滴泪 2024-07-25 04:00:22

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

int* pointer1, pointer2;

pointer2不是一个int *,它是简单的int
但使用 typedef 就不会发生这种情况:

typedef int* pInt;
pInt pointer1, pointer2;

它们现在都是 int * 了。

This can help you avoid some errors. For example in following code:

int* pointer1, pointer2;

pointer2 is not an int *, it is simple int.
But with typedefs this is not gonna happen:

typedef int* pInt;
pInt pointer1, pointer2;

They are both int * now.

梦晓ヶ微光ヅ倾城 2024-07-25 04:00:22

我的回答是明确的“不”。

为什么?

好吧,首先,您只需将单个字符 * 交换为另一个单个字符 p。 即增益。 仅此一点就应该阻止您这样做,因为做额外的毫无意义的事情总是不好的。

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

void foo(SomeType bar);

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

我不希望通过将其传递给 foo() 来更改 myBar 的含义。 毕竟,我是按值传递的,所以 foo() 只能看到 myBar 的副本,对吗? 当 SomeType 被别名表示某种指针时则不然! 特别是当该指针充当某种对象的引用时,其值基本上就是指针的含义:我不会关心指针本身不会改变(由于按值传递),我感兴趣的是对象是否改变(指针后面的对象)。

这适用于 C 指针和 C++ 智能指针:如果您隐藏它们是指向用户的指针这一事实,则会造成完全不必要的混乱。 所以,请不要给你的指针起别名。

(我相信类型定义指针类型的习惯只是一种误导性的尝试,试图隐藏作为程序员有多少颗星 http ://wiki.c2.com/?ThreeStarProgrammer 。)

My answer is a clear "No".

Why?

Well, first of all, you simply exchange a single character * for another single character p. That is zero gain. This alone should keep you from doing this as it is always bad to do extra stuff that's pointless.

Second, and that is the important reason, the * carries meaning that is not good to hide. If I pass something to a function like this

void foo(SomeType bar);

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

I do not expect the meaning of myBar to be changed by passing it to foo(). After all, I'm passing by value, so foo() only ever sees a copy of myBar right? Not when SomeType is aliased to mean some kind of pointer! Especially when that pointer acts as a reference to some kind of object whose value is basically the meaning of the pointer: I won't care that the pointer itself does not change (due to pass-by-value), I'm interested in whether the object changes or not (the object behind the pointer).

This applies both to C pointers and C++ smart pointers: If you hide the fact that they are pointers to your users, you will create confusion that is totally unnecessary. So, please, don't alias your pointers.

(I believe the habit of typedefing pointer types is just a misguided attempt to hide how many stars one has as a programmer http://wiki.c2.com/?ThreeStarProgrammer .)

用心笑 2024-07-25 04:00:22

假设感兴趣的语言是 C 进行讨论。尚未考虑 C++ 的后果。

对未标记的结构使用指针 typedef

问题 定义为指针的结构的大小提出了使用typedef(结构)指针的有趣侧面。

考虑无标签的具体(非不透明)结构类型定义:

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

成员的细节与此讨论完全无关; 重要的是,这不是像 typedef struct tag *tag; 这样的不透明类型(并且您无法通过没有标签的 typedef 定义此类不透明类型)。

提出的问题是“你如何找到该结构的大小”?

简短的答案是“仅通过该类型的变量”。 没有可与 sizeof(struct tag) 一起使用的标记。 例如,您不能有效地编写 sizeof(*Information),而 sizeof(Information *) 是指向指针类型,而不是结构类型的大小。

事实上,如果您想分配这样的结构,除非通过动态分配(或模仿动态分配的替代技术),否则无法创建一个结构。 无法创建其指针称为 Information 的结构类型的局部变量,也无法创建以下类型的文件范围(全局或静态)变量:结构类型,也没有办法将这样的结构(而不​​是指向这样的结构的指针)嵌入到另一个结构或联合类型中。

您可以 — 必须 — 写:

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

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

这有害吗?

这取决于你的目标。

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

它是一种只能与动态内存分配一起使用的类型。

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

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

但总体而言,它比启蒙更有可能引起混乱和焦虑。

总结

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

Discussion pitched assuming the language of interest is C. Ramifications for C++ have not been considered.

Using a a pointer typedef for an untagged structure

The question Size of a struct that is defined as a pointer raises an interesting side-light on using typedef for (structure) pointers.

Consider the tagless concrete (not opaque) structure type definition:

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

The details of the members are completely tangential to this discussion; all that matters is that this not an opaque type like typedef struct tag *tag; (and you can't define such opaque types via a typedef without a tag).

The question raised is 'how can you find the size of that structure'?

The short answer is 'only via a variable of the type'. There is no tag to use with sizeof(struct tag). You can't usefully write sizeof(*Information), for example, and sizeof(Information *) is the size of a pointer to the pointer type, not the size of the structure type.

In fact, if you want to allocate such a structure, you can't create one except via dynamic allocation (or surrogate techniques that mimic dynamic allocation). There is no way to create a local variable of the structure type whose pointers are called Information, nor is there a way to create a file scope (global or static) variable of the structure type, nor is there a way to embed such a structure (as opposed to a pointer to such a structure) into another structure or union type.

You can — must — write:

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

Apart from the fact that the pointer is hidden in the typedef, this is good practice — if the type of info changes, the size allocation will remain accurate. But in this case, it is also the only way to get the size of the structure and to allocate the structure. And there's no other way to create an instance of the structure.

Is this harmful?

It depends on your goals.

This isn't an opaque type — the details of the structure must be defined when the pointer type is typedef'd.

It is a type that can only be used with dynamic memory allocation.

It is a type that is nameless. The pointer to the structure type has a name, but the structure type itself does not.

If you want to enforce dynamic allocation, this seems to be a way to do it.

On the whole, though, it is more likely to cause confusion and angst than enlightenment.

Summary

It is, in general, a bad idea to use typedef to define a pointer to a tagless stucture type.

一笔一画续写前缘 2024-07-25 04:00:22

这(就像很多答案一样)取决于。

在 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.

It (like so many answers) depends.

In C this is very common as you are trying to disguise that an object is a pointer. You are trying to imply that this is the object that all your functions manipulate (we know it is a pointer underneath but it represents the object you are manipulating).

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

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

Underneath MYDB is probably a pointer at some object.

In C++ this is no longer required.
Mainly because we can pass things around by reference and the methods are incorporated into the class declaration.

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.
八巷 2024-07-25 04:00:22

不会。

一旦与 const 混合,你的日子就惨了。

typedef foo *fooptr;
const fooptr bar1;
const foo *bar2

bar1bar2 是同一种类型吗?

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

-- 编辑 --

添加引用文章的链接。

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

No.

It will make your life miserable the moment you mix it with const

typedef foo *fooptr;
const fooptr bar1;
const foo *bar2

Are bar1 and bar2 the same type?

And yeah, I am just quoting Herb Sutter's Guru. Much truth did she speak. ;)

-- Edit --

Adding link to cited article.

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

零時差 2024-07-25 04:00:22

这是风格问题。 您在 Windows 头文件中经常看到此类代码。 尽管他们更喜欢全大写版本而不是带有小写 p 前缀。

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

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

This is a matter of style. You see this kind of code very frequently in the Windows header files. Though they tend to prefer the all upper case version instead of prefixing with a lower case p.

Personally I avoid this use of typedef. It's much clearer to have the user explicitly say they want a Foo* than PFoo. Typedef's are best suited these days for making STL readable :)

typedef std::map<std::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;
水波映月 2024-07-25 04:00:22

使用 typedef 是为了使代码更具可读性,但将指针设置为 typedef 会增加混乱。 最好避免使用 typedef 指针。

Typedef is used to make code more readable, but making pointer as typedef will increase confusion. Better to avoid typedef pointers.

苄①跕圉湢 2024-07-25 04:00:22

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

list<const pSomeStruct> structs;

as

list<SomeStruct * const> structs;

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

请参阅此问题

If you do this, you will be unable to create STL containers of const pSomeStruct since the compiler reads:

list<const pSomeStruct> structs;

as

list<SomeStruct * const> structs;

which is not a legal STL container since the elements are not assignable.

See this question .

远山浅 2024-07-25 04:00:22

一般来说,没有。 在特定情况下,是的。

其他一些答案提到了一些结构,那就是仅指针类型。 我想到了一些仅指针类型的结构。 如果有人想到更多,我会将它们添加到列表中。

不透明类型

这些类型的实现对用户完全隐藏。 您通常会在标头中看到结构体 typedef,但没有该结构体的实现。 因此,您无法取消引用这些类型的值。 对此类型进行操作的所有函数都采用指向这些类型的指针。 在这些情况下,将指针添加到 typedef 是合适的。 您经常会看到这些称为“句柄”类型。

typedef struct handle_ * handle;

handle get_handle(string s);
void mutate_handle(handle h, value v);
void release_handle(handle h);

灵活数组成员类型

另一种仅指针类型是使用灵活数组成员 (FAM) 定义的类型。 FAM 类型中的最后一个成员是无约束数组。 您打算为这些类型动态分配存储,并且灵活数组被视为与结构内联。 您可以访问 FAM 类型中的字段,但不能取消引用整个对象。 在这里添加指向 typedef 的指针也是合适的。

typedef struct string {
    size_t capacity;
    size_t length;
    char buffer[];
} * string;

string string_new(void);
size_t string_length(string s);
void string_append(string * s, char c);
void string_delete(string * s);

In general, no. In specific cases, yes.

There are a couple constructs that some other answers alluded to, and that is pointer-only types. There are a couple pointer-only type constructs that come to mind. If anyone thinks of more I'll add them to the list.

Opaque Types

These are types where the type's implementation is totally hidden to the user. You will typically see a structure typedef in the header, but no implementation of that struct. Because of that you cannot dereference values of these types. All functions that operate on this type take pointers to these types. It is appropriate to add the pointer to the typedef in these situations. You often see these called "handle" types.

typedef struct handle_ * handle;

handle get_handle(string s);
void mutate_handle(handle h, value v);
void release_handle(handle h);

Flexible Array Member Types

Another pointer-only type are types that are defined with flexible array members (FAMs). The last member in a FAM type is an unconstrained array. You are intended to dynamically allocate storage for these types and the flexible array is treated as inline with the structure. You can access fields in a FAM type, but cannot dereference the whole object. It is also appropriate to add the pointer to the typedef here.

typedef struct string {
    size_t capacity;
    size_t length;
    char buffer[];
} * string;

string string_new(void);
size_t string_length(string s);
void string_append(string * s, char c);
void string_delete(string * s);
疯狂的代价 2024-07-25 04:00:22

Win32 API 几乎对每个结构(如果不是全部)都执行此操作,

POINT => *LPPOINT
WNDCLASSEX => *LPWNDCLASSEX
RECT => *LPRECT
PRINT_INFO_2 => *LPPRINT_INFO_2

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

Win32 API does this with just about every structure (if not all)

POINT => *LPPOINT
WNDCLASSEX => *LPWNDCLASSEX
RECT => *LPRECT
PRINT_INFO_2 => *LPPRINT_INFO_2

It's nice how it is consistent, but in my opinion it doesn't add any elegance.

相守太难 2024-07-25 04:00:22

typedef 的目的是隐藏实现细节,但是对指针属性进行 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);

然而,这只有效,因为你永远不会弄乱直接指向的内容。 根据我的经验,当你键入定义一些指针时,你在某些地方修改代码就变得很难阅读。

The purpose with typedef is to hide the implementation details, but typedef-ing the pointer property hides too much and makes the code harder to read/understand.
So please do not do that.


If you want to hide implementation details (which often is a good thing to do), do not hide the pointer part. Take for instance at the prototype for the standard FILE interface:

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

here fopen returns a pointer to some structure FILE (which you do not know the implementation details for). Maybe FILE is not such a good example because in this case it could have worked with some pFILE type that hid the fact that it is a pointer.

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

However, that would only work because you never mess around with the content that is pointed to directly. The moment you typedef some pointer that you some places modify the code becomes very hard to read in my experience.

寄风 2024-07-25 04:00:22

不久前,我会对这个问题回答“不”。 现在,随着智能指针的兴起,指针不再总是用星号“*”定义。 因此,类型是否是指针并没有什么明显的区别。

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

Some time ago, i'd have answered "no" to this question. Now, with the rise of smart pointers, pointers are not always defined with a star '*' anymore. So there is nothing obvious about a type being a pointer or not.

So now i'd say : it is fine to typedef pointers, as long as it is made very clear that it is a "pointer type". That means you have to use a prefix/suffix specifically for it. No, "p" is not a sufficient prefix, for instance. I'd probably go with "ptr".

没有伤那来痛 2024-07-25 04:00:21

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

本质上,如果您的代码永远不会取消引用指针,并且您只是将其传递给 API 函数(有时通过引用),那么 typedef 不仅会减少 * 的数量s 在你的代码中,但也建议程序员不要真正干预指针。

这也使得将来在需要时更容易更改 API。 例如,如果您更改为使用 ID 而不是指针(反之亦然),则现有代码不会中断,因为指针从一开始就不应该被取消引用。

This can be appropriate when the pointer itself can be regarded as a "black box", that is, a piece of data whose internal representation should be irrelevant to the code.

Essentially, if your code will never dereference the pointer, and you just pass it around API functions (sometimes by reference), then not only does the typedef reduce the number of *s in your code, but also suggests to the programmer that the pointer shouldn't really be meddled with.

This also makes it easier to change the API in the future if the need arises. For instance, if you change to using an ID rather than a pointer (or vice versa) existing code won't break because the pointer was never supposed to be dereferenced in the first place.

め七分饶幸 2024-07-25 04:00:21

以我的经验来看并非如此。 隐藏“*”会使代码难以阅读。

Not in my experience. Hiding the '*' makes the code hard to read.

你与昨日 2024-07-25 04:00:21

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

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

typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);

否则,我发现它们更令人困惑而不是有帮助。



The struck-out declaration is the correct type for a pointer to the signal() function, not of the signal catcher. It could be made clearer (using the corrected SigCatcher type above) by writing:

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

或者,声明 signal() 函数:

 extern SigCatcher signal(int, SigCatcher);

也就是说,SignalFunction 是一个指向带有两个参数(一个 int code> 和一个 SigCatcher)并返回一个 SigCatchersignal() 本身是一个函数,它接受两个参数(一个 int 和一个 SigCatcher)并返回一个 SigCatcher >。

The only time I use a pointer inside the typedef is when dealing with pointers to functions:

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

typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);

Otherwise, I find them more confusing than helpful.



The struck-out declaration is the correct type for a pointer to the signal() function, not of the signal catcher. It could be made clearer (using the corrected SigCatcher type above) by writing:

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

Or, to declare the signal() function:

 extern SigCatcher signal(int, SigCatcher);

That is, a SignalFunction is a pointer to a function which takes two arguments (an int and a SigCatcher) and returns a SigCatcher. And signal() itself is a function which takes two arguments (an int and a SigCatcher) and returns a SigCatcher.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文