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

问题描述

我想检测 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,回调可以根据 v_int 的值解码是访问 v_ptr 还是 type

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

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

,

Windows 用它们的 HANDLE 和资源 ID 做了很多这样的事情。

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

几乎所有操作系统都保留低内存区域。您大概可以假设 0 到 65535 的 16 位范围不是指针。除此之外,还不确定。

如果您的代码需要可移植到嵌入式 RTOS 或独立环境之类的东西,那么您不能假设任何关于指针的内容。

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