Кастинг дважды в одной строке - программирование
Подтвердить что ты не робот

Кастинг дважды в одной строке

Я видел этот код в проекте.

b Тип void*:

void *b = ...;
int a = (int) (unsigned long) b;

Является ли эта линия бессмысленной? Я имею в виду, что это так же, как a = (int) b во всех случаях?

4b9b3361

Ответ 1

Это, вероятно, избегает предупреждения компилятора в 64-разрядных Unix-системах, где unsigned long - это 64-разрядное количество и, следовательно, достаточно большое, чтобы удерживать указатель, но int - это 32-разрядное количество, которое недостаточно велико для того, чтобы удерживайте указатель. Приведение в (unsigned long) сохраняет все биты адреса; последующий листинг в int выбрасывает 32-битные адреса высокого порядка, но делает это, не получая предупреждения по умолчанию.

Чтобы продемонстрировать:

int main(void)
{
    void *b = (void *)0x12345678;
    int   a = (int)(unsigned long)b;
    int   c = (int)b;
    return a + c;
}

$ gcc -O3 -g -std=c99 -Wall -Wextra -c ar.c
ar.c: In function ‘main’:
ar.c:5:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
$

Использование GCC 4.7.1 в Mac OS X 10.8.4, по умолчанию 64-битная компиляция.

Интересно спрогнозировать, что будет сделано со значением "части адреса".

Ответ 2

Прямо typecasting для указателя на меньший тип say int может привести к ошибке компиляции некоторого компилятора (например, Clang) в среде x64 бит.

Например:

 void *p = GetSomeAddress;
 int i = (int)p;  //error on compilers like Clang.

Решение:

int i = (int)(unsigned long)p;

или

int i = (int)(long)p;

Это связано с тем, что в Unix в модели LP64 длинная 64-разрядная версия.

В таких случаях вам нужно тщательно изучить, почему вам нужен метод typecast от указателя к int или другому меньшему типу, который может привести к потере данных.

Этот вопрос также может помочь вам. Как мне обрабатывать "cast from 'void * to' int loses precision" при компиляции 32-битного кода на 64-битной машине?

Ответ 3

Я тоже вижу это в своем проекте.

В моем случае содержимое "b" заполняется другими источниками/промежуточным программным обеспечением, используемым для межпроцессного взаимодействия.

После заполнения "b" программа получит содержимое "b" с приведением в правильное поле "a". приложение затем использует "a" для обработки.

В моем проекте используется char * вместо void *.