【问题标题】:Cast 32 bit int to 64 void * pointer without warning将 32 位 int 转换为 64 void * 指针而不发出警告
【发布时间】:2011-11-15 14:04:17
【问题描述】:

我在 C 中有一个“通用”链接链接,它使用 void * data 将数据存储在节点中。

insertNode(linkedList * list, void *data);

//Storing/retrieving a string works fine;
char *str="test"; 
insertNode(list, str);
char *getback=(char *)node->data;

//Storing/retrieving an Int results a cast warning
int num=1;
insertNode(list,(void *)num);
int getback=(int)node->data;

这是因为 int 是 32 位的,而 void * 在 x64 机器上是 64 位的。消除此错误的最佳做法是什么?

【问题讨论】:

    标签: c 64-bit void-pointers


    【解决方案1】:

    使用intptr_tuintptr_t。它们是与指针大小相同的整数:

    #include <stdint.h>
    ...
    intptr_t num = 1;
    insertNode(list, (void *) num);
    intptr_t getback = (intptr_t) node->data;
    

    当然,您可以存储的最大值取决于系统,但您可以在编译时通过INTPTR_MININTPTR_MAX 对其进行检查。

    【讨论】:

    • 您也可以通过intptr_t 使用中间转换来消除愚蠢的警告。
    • 如何进行“中级演员”?
    • @Usavich:我认为 R.. 的意思类似于 insertNode(list, (void *) ((intptr_t) num))int getback = (intptr_t) node-&gt;data
    • +1 虽然标准说整数到指针,反之亦然转换是特定于实现的,但 C99 标准库引入了 intptr_tuintptr_t
    【解决方案2】:

    使用void * 成员来存储整数值并不是很好的做法——除此之外,无法保证以这种方式存储的整数范围。如果您想在结构中存储指针或整数,那么您应该使用union

    union data {
        void *p;
        int i;
    };
    
    insertNode(linkedList * list, union data data);
    
    // Storing/retrieving a string:
    char *str="test"; 
    union data d;
    d.p = str;
    insertNode(list, d);
    char *getback = node->data.p;
    
    // Storing/retrieving an int:
    int num = 1;
    union data d;
    d.i = num;
    insertNode(list, d);
    int getback = node->data.i;
    

    如果您有一个支持 C99 结构的编译器,您可以通过避免使用本地 union 变量来使其更简洁:

    // Insert a string
    insertNode(list, (union data){ .p = str});
    
    // Insert an int
    insertNode(list, (union data){ .i = num});
    

    【讨论】:

      【解决方案3】:

      你可以转换两次:insertNode(list, (void *)(uint64_t) num);

      或者您可以对 num 使用“unsigned long”而不是 int。至少根据我的经验,sizeof(unsigned long) == sizeof(void *) 在 32 位和 64 位系统上都是如此。使用 uintptr_t 可能更正确;我已经有一段时间没有阅读标准了。

      【讨论】:

      • sizeof(unsigned long) != sizeof(void *) 在 Windows 64 位上
      • 不在 MSVC 上,但我怀疑它们在 gcc 上是一样的,不是吗?
      • 很公平。在使用 gcc 的 32/64 位 MIPS 中确实如此。
      【解决方案4】:

      你确定你正在做你真正想做的事吗?在带有字符串的第一个示例中,您将指向字符串文字的指针传递给 insertNode,而在第二个示例 ((void *)num) 中,您将 int 的值转换为指向 void 的指针。您是否真的想这样做:insertNode(list,(void *)&amp;num);,即像在第一个示例中那样传递对数据的引用?

      顺便说一句,char *str="test"; 使 str 指向一个字符串字面量,它是只读的。所以你真的应该做const char *str="test";。如果你想要一个普通的(可写的)字符串,那么char str[] = "test";

      如果您已经知道这些事情并且真的想在 void * 中存储一个 int,我深表歉意,我无法想象您为什么会这样做。

      编辑:如果您真的想要通用存储空间,那么联合将是一种安全的方法。绝对不能保证 int 适合标准 C 中的 void *,尽管在大多数实现中它可能确实如此。

      【讨论】:

      • 是的,我确实想将int 存储到void * 中,因为在这种情况下,int 的 malloc 似乎是不必要的。该字符串只是一个简单的示例,而不是我实际使用它的方式。还是谢谢。
      猜你喜欢
      • 1970-01-01
      • 2017-01-12
      • 2013-11-18
      • 1970-01-01
      • 1970-01-01
      • 2014-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多