как я могу сохранить указатель на смещенное местоположение в распределенной области памяти в C?

Я пытаюсь сделать очень простую Hashtable с библиотеками, которые у меня есть. Строка, которую я пытаюсь создать, содержит либо C-строку, либо int в качестве ключа. Значение может быть 4 различных типов. Если это структура, я пытаюсь сохранить указатель в распределенной области памяти. Однако в моем мире это не следует той же логике, что и поля без указателя, и я получаю:

error C2106: '=' : left operand must be l-value when I try to store pointer as value:

Вот код

static void MakeRow(UtiHashtable_t *Hashtable, void *Key, void *Value, void *Row)
{
    int     KeySize, ValueSize;

    KeySize = sizeof(char) * Hashtable->KeyStringLength;
    ValueSize = GetValueSize(Hashtable);
    Row = malloc(KeySize + ValueSize);

    if (Hashtable->KeyType ==  MY_HASHTABLE_TYPE_STRING)  
        MyStrcpy((char *)Row, (char *)Key, Hashtable->KeyStringLength); 
    else if (Hashtable->KeyType ==  MY_HASHTABLE_TYPE_INT)
        ((int *)Row)[0] =  *(int *)Key;
    else
        MyAssert(0);

    switch (Hashtable->ValueType)
    {
    case MY_HASHTABLE_TYPE_STRING:
        MyStrcpy((char *)Row + KeySize, (char *)Value, Hashtable->ValueStringLength); 
        break;
    case MY_HASHTABLE_TYPE_INT: 
        *(int *)((char *)Row + KeySize) =  *(int *)Value;
        break;
    case MY_HASHTABLE_TYPE_DOUBLE: 
        *(double *)((char *)Row + KeySize) =  *(double *)Value;
        break;
    case MY_HASHTABLE_TYPE_STRUCT: 
        (int *)((char *)Row + KeySize) = (int *)Value;
        break;
    default:
        MyAssert(0);
    }
}

Я знаю, что это действительно просто и получит несколько отрицательных голосов, но помимо ответа я хотел бы иметь объяснение, почему это удаление * не делает его указателем.

Компилятор позволяет:

(int *)Value = (int *)Key;

так почему бы не:

(int *)((char *)Row + KeySize) = (int *)Value;

Спасибо и BR-Матти


person char m    schedule 22.11.2011    source источник
comment
Как вы пришли к утверждению, что (int *)Value = (int *)Key будет действительным? Приведение всегда применяется к выражению, а не к переменной, и результатом всегда является rvalue.   -  person Jens Gustedt    schedule 22.11.2011
comment
@jens: компилятор не возражает, если адрес Value будет изменен на адрес Key.   -  person char m    schedule 22.11.2011
comment
это не имеет особого смысла. Конечно, компилятор будет возражать. Вы не можете изменить адреса переменных, это просто переменная в C, место в памяти с определенным адресом.   -  person Jens Gustedt    schedule 22.11.2011


Ответы (2)


Использование приведения к lvalue устарело.

Кроме того, некоторые системы не позволяют размещать int или указатели в произвольных местах памяти из-за проблем с выравниванием.

Что вам нужно сделать, так это memcpy значение указателя туда, где вы хотите. И когда вы хотите использовать указатель, вам нужно memcpy вернуть его обратно в переменную указателя.

person Klas Lindbäck    schedule 22.11.2011
comment
Спасибо. в любом случае мой C-компилятор Visual Studio 2010 не позволяет этого. и я не думаю, что это действительно работает для структур (как в моем случае). - person char m; 22.11.2011
comment
Благодарность! memcpy может быть ответом. я вернусь к вам, когда я сделал некоторые испытания. - person char m; 22.11.2011

Вы остановили разыменование * с левой стороны, поэтому присваивание больше не имеет смысла.

person Josh Matthews    schedule 22.11.2011
comment
извини но я не понял. нет разыгрывания ссылок ни для одного размера. это: (int *)((char *)Row + KeySize) = (int *)Value; - person char m; 22.11.2011
comment
как я могу разыменовать его, если я хочу сохранить там указатель? если я добавлю * к заголовку левой стороны, это, естественно, другая ошибка: «int» отличается уровнями косвенности от «int *» - person char m; 22.11.2011
comment
попробуй *(int **)((char *)Row + KeySize) = (int *)Value - person Jens Gustedt; 22.11.2011