使用 void* 参数传递整数或指针

Use a void* argument to pass integer OR a pointer

我想检测 void* 类型输入函数参数的值是整数还是指针。目前,我只传递整数(这是 Midnight Commander 来源):

mc_event_raise (MCEVENT_GROUP_CORE, 
    "clipboard_file_from_ext_clip",
        (void*)(intptr_t)clip_id);

然而,有时我也想在同一个参数中传递一个字符串 (char *),因为扩展 API 会很困难。我知道这是错误的,但是,也许有一种完全合法的方式来获得这种效果?我的想法: – 地址通常对齐到 4 或 8 个字节,所以我可以从 clip_id 中跳过这些值(跳过它们)然后解码该值? if (data % 8) then clip_id = decode_clip_id(data); ? – 也许指针不能小到 10…20,一个简单的检查就足够了吗? – 其他想法……?

这样的问题可以用包含联合和标签的结构来解决。

struct EventData {
    enum { EV_IS_INT, EV_IS_PTR } type;
    union {
        intptr_t v_int;
        void * v_ptr;
    };
};

所以,你可以传递一个指向这个EventData的指针,回调可以根据[=15=的值解码是访问v_int还是v_ptr ].

    struct EventData *ed = makeEventData (EV_IS_INT, clip_id);
    mc_event_raise (MCEVENT_GROUP_CORE, 
                    "clipboard_file_from_ext_clip",
                    ed);

如果事件是异步完成的,您可能需要动态创建事件,然后回调函数必须在回调完成时释放内存。

Windows 用他们的 HANDLE 和资源 ID 做了很多这样的黑客行为。

您的整数需要有定义的有效范围。超出该范围的任何东西都可能是指针。

几乎所有操作系统都保留低位内存区。您可能会假设 16 位范围 0 到 65535 不是指针。除此之外变得不确定。

如果您的代码需要可移植到嵌入式 RTOS 或独立环境中,那么您不能对指针做任何假设。

在任何情况下,您可能需要某种函数来创建值以传递到您的 void* 中,其中包含 assertabort 以避免意外创建无效值。