Приведите 32-битный int к 64 void * указателю без предупреждения - PullRequest
3 голосов
/ 12 сентября 2011

У меня есть «общая» связанная ссылка в 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 * является64 бит на машине x64.Как лучше избавиться от этой ошибки?

Ответы [ 4 ]

13 голосов
/ 12 сентября 2011

Используйте intptr_t или uintptr_t. Они являются целыми числами того же размера, что и указатель:

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

Конечно, максимальное значение, которое вы можете сохранить, зависит от системы, но вы можете проверить его во время компиляции с помощью INTPTR_MIN и INTPTR_MAX.

2 голосов
/ 13 сентября 2011

Использование члена 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});
0 голосов
/ 13 сентября 2011

Вы уверены, что делаете то, что действительно хотите делать? В первом примере со строкой вы передаете указатель на строковый литерал в insertNode, а во втором примере ((void *)num) вы приводите значение int к указателю на void. Вы действительно хотели сделать это: insertNode(list,(void *)&num);, т.е. передать ссылку на данные, как вы делали в первом примере?

Кроме того, char *str="test"; указывает на строковый литерал str, который доступен только для чтения. Так что вы действительно должны делать const char *str="test";. Если вам нужна нормальная (доступная для записи) строка, тогда char str[] = "test";.

Извините, если вы уже знали эти вещи и действительно хотели сохранить int в void *, я просто не могу представить, почему вы это сделали.

Редактировать: Если вы действительно хотите общее хранилище, тогда объединение будет безопасным подходом. Нет абсолютно никакой гарантии, что int будет соответствовать void * в стандартном C, хотя в большинстве реализаций он, вероятно, подходит.

0 голосов
/ 12 сентября 2011

Вы можете разыграть его дважды: insertNode (list, (void *) (uint64_t) num);

Или вы можете использовать "unsigned long" для num вместо int. По крайней мере, по моему опыту, sizeof (unsigned long) == sizeof (void *) в 32- и 64-разрядных системах. Использование uintptr_t может быть более правильным; я давно не читал стандарты.

...