Подтвердить что ты не робот

Почему я могу использовать int и BOOL для void *, но не плавать?

void* является полезной особенностью языков C и производных. Например, можно использовать void* для хранения указателей объектов objective-C в классе С++.

Недавно я работал над структурой преобразования типов и из-за ограничений по времени был немного ленив - поэтому я использовал void*... Как этот вопрос возник:

Почему я могу использовать метод int для void *, но не float для void *?

4b9b3361

Ответ 1

BOOL не является типом С++. Вероятно, он определен или определен где-то, и в этих случаях он будет таким же, как int. Windows, например, имеет это в Windef.h:

    typedef int                 BOOL;

поэтому ваш вопрос сводится к тому, почему вы можете ввести тип int в void *, но не float to void *?

int to void * нормально, но обычно не рекомендуется (и некоторые компиляторы будут предупреждать об этом), потому что они по сути являются одинаковыми в представлении. Указатель в основном представляет собой целое число, указывающее на адрес в памяти.

float to void * не подходит, потому что интерпретация значения float и фактических битов, представляющих его, различна. Например, если вы выполните:

   float x = 1.0;

что он делает, он устанавливает 32-битную память в 00 00 80 3f (фактическое представление значения float 1.0 в одиночной точности IEEE). Когда вы бросаете поплавок в пустоту *, интерпретация неоднозначна. Вы имеете в виду указатель, указывающий на местоположение 1 в памяти? или вы имеете в виду указатель, указывающий на местоположение 3f800000 (предполагая, что в нем мало конца)?

Конечно, если вы уверены, какой из двух случаев вы хотите, всегда есть способ обойти проблему. Например:

  void* u = (void*)((int)x);        // first case
  void* u = (void*)(((unsigned short*)(&x))[0] | (((unsigned int)((unsigned short*)(&x))[1]) << 16)); // second case

Ответ 2

Указатели обычно представляются внутри машины целыми числами. C позволяет вам перемещаться между типом указателя и целым типом. (Значение указателя может быть преобразовано в целое, достаточно большое, чтобы удерживать его и обратно.)

Использование void* для хранения целочисленных значений в нетрадиционных. Это не гарантируется языком для работы, но если вы хотите быть неаккуратным и сдерживать себя для Intel и других распространенных платформ, он будет в основном очищаться.

Эффективно то, что вы делаете, использует void* как универсальный контейнер, однако многие байты используются машиной для указателей. Это отличается от 32-разрядных и 64-разрядных машин. Поэтому преобразование long long в void* приведет к потере бит на 32-битной платформе.

Что касается чисел с плавающей запятой, намерение (void*) 10.5f неоднозначно. Вы хотите округлить 10.5 до целого числа, а затем преобразовать это в бессмысленный указатель? Нет, вы хотите, чтобы бит-шаблон, используемый FPU, был помещен в бессмысленный указатель. Это можно сделать, назначив float f = 10.5f; void *vp = * (uint32_t*) &f;, но предупреждайте, что это просто абсурд: указатели не являются общим хранилищем для бит.

Лучшим общим хранилищем для бит является char массивы, кстати. Языковые стандарты гарантируют, что память можно манипулировать с помощью char*. Но вы должны учитывать требования к выравниванию данных.

Ответ 3

Стандарт говорит, что 752 Целое число может быть преобразовано в любой тип указателя. Не говорит ничего о преобразовании указателя-float.