【问题标题】:compiler warning - cast from pointer to integer of different size编译器警告 - 从指针转换为不同大小的整数
【发布时间】:2013-02-05 15:49:36
【问题描述】:

我正在尝试创建一个可以保存通用值的结构。下面的代码有效,但我收到关于从指针转换为整数的编译器警告。这是在 64 位系统上。

struct node
{
    void *key;
    void *value;
};

void insert(struct node *ht, void *key, void *value)
{
    ht->key = key;
    ht->value = value;
    return;
}

int main()
{
    struct node *t = (struct node *)malloc(sizeof(struct node));
    insert(t, (void *)3, (void *)5);
    printf("[%d]->[%d]\n", (int)t->key,(int)t->value);
    free(t);
    return 0;
}

我什至不确定这是否是正确的方法。我有点破解它。请让我知道是否有适当的方法来做到这一点。

【问题讨论】:

  • 您是否有理由不只是使用ints 开始?
  • 在C语言中,请不要cast the return value of malloc()
  • 如果您要使用 void 指针,请使用它们来存储指针,而不是整数。 (并且有支持和反对从malloc() 转换返回值的论据;你没有 来避免它,但你应该知道为什么 你这样做或不这样做铸件。)
  • 您可能有 64 位指针,但您可能仍在使用 32 位整数。 (或者不太可能,反之亦然!)
  • 为什么使用指针来存储 int 数据?

标签: c generics


【解决方案1】:

当从void * 转换为int 时,编译器会尝试警告您丢失位。它不知道void *实际上是int演员,所以丢失的位是没有意义的。

双重演员可以解决这个问题(int)(uintptr_t)t->key
它首先将void * 转换为uintptr_t(大小相同,无警告),然后将uintptr_t 转换为int(数字对数字,无警告)。
您需要包含 <stdint.h> 才能拥有 uintptr_t 类型(与指针大小相同的整数类型)。

【讨论】:

  • sizeof(size_t) 不保证等于sizeof(void *)(Windows 64 上的播放状态是什么?)。如果您想要一个指针大小的可靠类型,请使用来自<stdint.h>(或<inttypes.h>)的uintptr_t
  • @JonathanLeffler,我认为size_t 适用于 WIN64(与 long 不同),但原则上你是对的。我会改变的。
  • 我不建议双重演员。第一个不一定是必要的。第二个不会更好。
  • @JoshPetitt,为了克服严格的编译器警告,双重转换可能是必要的。唯一的选择是以不同的方式设计数据结构,这样会更好,但并不总是适用。
  • @JoshPetitt,你说得对,我提供了简单的解决方案,而不是基本解决方案。但是使用void * 携带任意类型(包括整数)是非常常见和有用的,但没有更好的选择。
【解决方案2】:

需要记住的一点是,在 64 位系统中,指针是 64 位值[内存地址]。

int 只是一个 32 位的值,无论您使用什么架构。每当您尝试将 64 位值分配给 32 位值而不显式转换它时,编译器都会抛出警告 [授予,它仍然可以工作,但通常不是好的做法。]

如果您不反对使用无符号整数,使用 uint_64t 或类似的东西可能会更容易,这将避免 64 位到 32 位的赋值(uint_64t 是无符号的 64 位 int)

希望对您有所帮助。

你可以做的一件事是:

int key = 3;
int value = 5;
insert(t, (void *) &key, (void *) &value);
printf("[%d]->[%d]\n", (int) *(t->key), (int) *(t->value));

但是,在做这样的事情时要非常小心。除非您可以保证设置了指针并且它的值/类型不变,否则不可能绝对知道该指针存储的值是什么。除非您添加一个枚举字段或存储存储在指针位置的值的类型的东西——但这违背了目的。

【讨论】:

  • OP 还必须小心不要在函数中做这样的事情。一旦函数返回,整数将“在堆栈上”并且无效。
【解决方案3】:

您发布的代码有很多问题。

第一:

printf("[%d]->[%d]\n", (int)t->key,(int)t->value);

打印指针时,打印指针。使用 %p。见这里:

http://www.cplusplus.com/reference/cstdio/printf/

第二:

insert(t, (void *)3, (void *)5);

我不确定您预期会发生什么,但您存储的是 ADDRESS 而不是 VALUE。 (即,您将键设置为指向地址 3 内容的指针,并将值设置为指向地址 5 内容的指针)。

第三:

struct node *t = (struct node *)malloc(sizeof(struct node));

在这里你已经分配了节点,但是你还没有分配任何东西来保存内容。您的节点仅包含一些指针(地址),它不包含任何值。我不确定这是否是你想要的。

最后,您的编译器正确地警告您。您有可能会失去精确度。就像@JonathanLeffler 所说,使用 uintptr_t。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 2014-02-14
    • 1970-01-01
    • 2012-03-04
    • 2019-08-13
    相关资源
    最近更新 更多