Is this code well defined (Casting HANDLE)
There's many instances of code similar to this in the codebase I'm working in these days. This is a thin C wrapper aroundthe OS API.
// From the OS
HANDLE CreateObject();
void CloseHandle(HANDLE);
typedef struct tag开发者_如何学JAVAFOO {} 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
}
}
This seems to work and I want to avoid touching it if I can, but is this well defined? It seems very fishy to me
The C99 standard says:
6.7.2.1 Structure and union specifiers
Syntax
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
Officially, that precludes your empty structure definition (and so does §6.5.2.1 in the C89 standard); there should be at least one member in the structure. However, you have to push GCC fairly hard to get it to complain; I used -std=c99 -pedantic
and only with the -pedantic
did it warn 'struct has no members'.
In my view, you would be better off (more strictly portable) with:
typedef struct tagFOO FOO;
Or, even using:
typedef struct FOO FOO;
The intent of the HANDLE definition is to be an opaque type, one that you can't make any assumptions about. In practice we know it's a pointer, and because of Windows famed backwards compatibility this is unlikely to ever change.
This does have a huge code smell, and if you have half an excuse I'd refactor it. But I don't think you're taking a huge risk if you leave it alone.
Worst case: HANDLE
is actually a 64-bit integer value, FOO*
is a 32-bit pointer. Casting loses information, and checking foo != NULL
is wrong (because it could be a valid value for the handle).
This is indeed very fishy.
精彩评论