将类型转换为无效*是错误/危险的吗?

Ign*_*kas 4 c type-conversion

整个代码是用ANSI C编写的,它应该保持不变.我有一个像这样定义的回调:

typedef enum {
    Event_One,
    Event_Two,
    Event_State
} EventEnum;

typedef void (*callback)(EventEnum event, void* data);
Run Code Online (Sandbox Code Playgroud)

回调接收者data根据event值解释.这是组件之间的契约.有时它是指向结构的指针,有时它可能是一个字符串,其他情况可能是其他数据.我正在定义一个额外的event并设置一个新的"合同",这data是一个枚举.像这样:

typedef enum {
    State_Initial = 0,
    State_Running,
    State_Final
} StateEnum;
Run Code Online (Sandbox Code Playgroud)

然后代码中的某个地方我有一个回调函数,就是这样做的

void ProcessEvent (EventEnum event, void* data)
{
    if (event == Event_State)
    {
         StateEnum state = (StateEnum)data; /* <<<<<<<<<<< */
         switch (state) {
         case State_Initial:
             <...>
             break;
         case State_Running:
             <...>
             break;
         case State_Final:
             <...>
             break;
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的回调被调用如下:

{
    callback infoCallback = ProcessEvent; /* This is only for example,
                                             done during initialization */
    <...>
    StateEnum someState = State_Running;
    <...>
    infoCallback(Event_State, (void*)someState); /* <<<<<<<<<<<<<<<<<<< */
}
Run Code Online (Sandbox Code Playgroud)

有什么根本性的错误类型映射void*StateEnum反之亦然?这种方式有什么可能的陷阱?关于可测试性和可维护性的任何想法?

编辑:代码编译,链接和运行正常.我想知道为什么不应该这样做,以及是否有任何真正的原因必须更改代码.

Alo*_*hal 5

只有指向对象的指针(即非函数)才能转换void *回来.您无法将非指针转换为void *和返回.所以,将您的电话改为:

infoCallback(Event_State, &someState);
Run Code Online (Sandbox Code Playgroud)

你的功能是:

StateEnum *state = data;
switch (*state)
...
Run Code Online (Sandbox Code Playgroud)

从标准(6.3.2.3):

整数可以转换为任何指针类型.除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示.

任何指针类型都可以转换为整数类型.除非先前指定,否则结果是实现定义的.如果结果无法以整数类型表示,则行为未定义.结果不必在任何整数类型的值范围内.

所以,你正在做的是实现定义.如果您的实现将其定义为可以转换int为指针并返回,则代码将起作用. 一般来说,它不便携.有关更多详细信息,请参阅comp.lang.c上的此主题.

C99另外限定类型intptr_tuintptr_t,它们是整体的类型,以及它是保证一个转换void *到它们并返回.

  • 这不是POSIX 2003对'dlsym`有技术更正的确切原因吗?`dlsym`可以用来在运行时动态查找函数指针,但是C99标准说`void*`(`dlsym`的返回值)转换为函数指针是未定义的,因此必须发布技术更正来解释一个有效的解决方法.这可以在"dlsym"的许多联机帮助页中找到. (2认同)