函数参数中的struct关键字和常量正确性

4

我的库中有一个不透明类型,定义如下:

typedef struct MyOpaqueType* MyType;  // easier to type for client code

我无法使用typedef传递指向常量结构的指针,因此某些函数看起来像:

void UsePointerToConst ( const struct MyOpaqueType * )

替代方法:

void UserPointerToConst( const MyType ) // can't use, is really constant pointer

因此,基于此,我有两个问题: 在参数列表中,struct关键字只在C语言中必要吗? 有更好的方法吗?我应该创建一个类似于typedef的东西吗?

typedef const struct MyOpaqueType* ConstantMyType; ?

4
Win32正是这样做的:LPSTR(指向以空字符结尾的字符串的指针)与LPCSTR(指向const空字符结尾的字符串的指针)等等。 - Jon
第二个typedef是解决问题的合理方案。 - Bill
1
<挑衅>Win32采用这种方式并不意味着任何人都应该复制它的坏习惯。</挑衅> - Fred Foo
3个回答

5
在参数列表中使用struct关键字仅在C语言中必需吗? 是的。请参阅Jens Gustedt的答案。
有更好的方法来做这件事吗?
只需将结构体进行typedef,而不是指针。这样做更好,因为:
  • 您只需要一个typedef,而不是每个类型{MyOpaqueType,MyOpaqueType *,MyOpaqueType const *,MyOpaqueType *const和MyOpaqueType const *const}以及所有涉及restrict(在C++中不存在)的变量和变量的变量,
  • 用户清晰地了解指针语义适用,即传递数据类型实际上是指针复制的问题(无性能担忧),用户更不可能忘记清理后使用,C++用户可以使用智能指针,并且
  • 这是一种常见的C约定(想想FILE *)。
同时也没有危险,当某人忘记*时,会得到编译器错误提示。

4
它存在,但是不完整。你仍然可以使用typedef来定义它。 - Alan Stokes
是的,但隐藏这个不透明句柄是指针的概念是我想保留的。typedef struct MyOpaqueType* MyType是该代码多年来使用的库习语。虽然我可能不理解你的意思。 - Cat Zimmermann
@Cat 这是一个常见的 C 习惯用法。C++ 有些不同 - struct 关键字引入了一个新的类型名称,例如。你可以使用两个 typedef(对于 const 和非 const),但惯用的 C++ 可能会像我在我的答案中建议的那样做。 - Alan Stokes
@Cat:我回答时很匆忙,现在补充一下为什么指针typedef对你的问题不是一个好主意。 - Fred Foo
不建议隐藏 typedef 的目标是指针。+1 - bta
我喜欢提醒使用明显指针语义时传达的信息。谢谢。 - Cat Zimmermann

3
在C++中,如果没有其他同名的标识符,使用与结构体同名的typedef会被默认为有效。因此,针对接收struct stat*作为参数的函数stat等情况会出现这种情况:
int stat(const char *path, struct stat *buf);

在 C++ 中甚至允许这样做(这是一个真实例子)。
所以最好始终使用类的前向声明,例如:
typedef struct toto toto;

在标识符和结构名称空间中保留令牌toto。然后可以为C和C++声明函数接口。但如果您想从C中访问它,请不要忘记使用extern "C"

另请参阅:SO上的此答案C ++中结构标记不是标识符


1
准确地说,在 C++ 中,与 C 一样,用户自定义类型的标识符和其他标识符被分开保留,但是当在作用域中查找标识符时,如果该标识符未位于全局标识符空间中,则它还将在用户自定义类型标识符空间中搜索...这是一种微妙的区别。 - David Rodríguez - dribeas
@David,是的,它甚至允许更荒谬的事情,比如首先使用裸字作为对struct的引用,然后再定义变量。C++是一种非常上下文敏感的语言,但我们已经知道了,不是吗。 - Jens Gustedt

2
你在C++中根本不需要typedef。只需使用前向声明即可:
struct MyType;

然后根据需要传递 MyType const *MyType *MyType const & 等参数。


我不想传递结构体,只想传递指向结构体的指针,因为结构体并不存在,仅存在于类型安全性方面。 - Cat Zimmermann
1
@Cat 它绝对存在;你已经声明了它,所以它存在。你不必定义它就可以让上面的代码工作。试试看! - Alan Stokes
即使您从未定义该结构的外观,您仍然可以使用类似于这样的前向声明,以允许您创建指向具有该名称的结构的指针。只是在您没有定义该结构的情况下不要尝试取消引用它们... - bta
哦,我明白你的意思了。抱歉,我读你的评论太快了。C代码参数不是必须写成PublicFunction(struct MyType* t)吗?我认为PF(MyType t)更容易阅读。 - Cat Zimmermann
1
如果你需要在 C 和 C++ 中都起作用,写 typedef struct MyType MyType;PF(MyType * t)既易于阅读,又明确表明正在发生的事情。 - Alan Stokes

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