在我最近工作的代码库中有许多与此类似的代码实例。这是围绕OS API的瘦C包装器。
// From the OS
HANDLE CreateObject();
void CloseHandle(HANDLE);
typedef struct tagFOO {} FOO;
FOO* Foo_New()
{
return (FOO*)CreateObject();
}
void Foo_Delete(FOO* foo)
{
if(foo != NULL)
{
CloseHandle((HANDLE)foo);
}
}
void Foo_Bar(FOO* foo)
{
if(foo != NULL)
{
HANDLE h = (HANDLE)foo;
// Do something interesting with h
}
}
这似乎有效,如果可以,我想避免接触它,但是这个定义得很好吗?这对我来说似乎非常可疑
答案 0 :(得分:2)
HANDLE定义的意图是一个不透明的类型,你无法做出任何假设。在实践中,我们知道它是一个指针,并且由于Windows具有向后兼容性,因此不太可能发生变化。
这确实有巨大的代码味道,如果你有一半的借口我会重构它。但是,如果你不管它,我认为你不会冒很大的风险。
答案 1 :(得分:2)
C99标准说:
6.7.2.1结构和联合说明符
语法
struct-or-union-specifier: struct-or-union identifieropt { struct-declaration-list } struct-or-union identifier struct-or-union: struct union struct-declaration-list: struct-declaration struct-declaration-list struct-declaration
正式地说,这排除了你的空结构定义(C89标准中的§6.5.2.1也是如此);结构中至少应有一个成员。但是,你必须非常努力地推动GCC抱怨它;我使用-std=c99 -pedantic
并且仅使用-pedantic
警告'结构没有成员'。
在我看来,你会更好(更严格的便携性):
typedef struct tagFOO FOO;
或者,甚至使用:
typedef struct FOO FOO;
答案 2 :(得分:0)
最坏情况:HANDLE
实际上是64位整数值,FOO*
是32位指针。转换丢失信息,检查foo != NULL
是错误的(因为它可能是句柄的有效值)。
这确实非常可疑。