Как бросить от bool до void *? - PullRequest
2 голосов
/ 03 марта 2009

Я пытаюсь собрать cairomm для gtkmm в windows, используя mingw. Обрывы компиляции при вызове функции, у которой есть параметр, который делает reinterpret_cast из bool в void *.

cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS, reinterpret_cast<void*>(true), NULL);

Вот где код ломается, и причиной является «недопустимый reinterpret_cast от bool до void *». Почему это происходит, и как я могу изменить эту строку, чтобы она компилировалась? Нужна помощь

Ответы [ 7 ]

13 голосов
/ 03 марта 2009

Я вижу, что это пользовательские данные, и у вас есть контроль над тем, что делается со значением, сначала приведите bool к int: reinterpret_cast<void *> (static_cast<int> (true)). Это имеет смысл в том смысле, что параметр void * занимает место шаблонных функций в этой библиотеке ANSI-C. Все, что вам нужно, это истинное / ложное значение. Таким образом, не должно быть никакой опасности во временном кодировании этого как указателя, пока это хорошо документировано как таковое. На самом деле, вам было бы лучше с этим: reinterpret_cast<void *> (1) или reinterpret_cast<void *> (+true).

3 голосов
/ 03 марта 2009

Похоже, должно работать, согласно стандарту. Раздел 3.9.1-7 говорит, что bool является целочисленным типом, а 5.2.10-5 говорит, что значение целочисленного типа может быть явно преобразовано в указатель с помощью reinterpret_cast. Похоже, ваш компилятор не полностью стандартный.

Не могли бы вы изменить значение true на 1? Преобразование между целыми числами и типами указателей является старой и бесчестной традицией в C и, следовательно, в C ++, и было бы удивительно найти компилятор, который бы этого не делал.

Или, если вам действительно нужно это сделать, попробуйте (void *) true. Затем вымойте руки.

1 голос
/ 03 марта 2009

Единственный компилятор, который у меня есть, жалуется на это - GCC (MinGW с GCC 3.4.5) - и я не знаю почему. Стандарт, кажется, четко указывает, что это разрешено:

3.9.1 Основные типы

...

Типы bool, char, wchar_t и целочисленные типы со знаком и без знака все вместе называются целочисленными типами.

5.2.10. Переинтерпретация:

...

значение целого типа или Тип перечисления может быть явно преобразован в указатель.

Тем не менее, обходной путь monjardin использования reinterpret_cast<void *> (static_cast<int> (true)) или reinterpret_cast<void *> (1) - разумные обходные пути.

1 голос
/ 03 марта 2009

reinterpret_cast - это плохая идея . Расскажите подробнее о проблеме, которую вы пытаетесь решить, и, возможно, мы найдем решение, не прибегая к переосмыслению. Почему вы хотите конвертировать bool в void *?

0 голосов
/ 04 марта 2009

В некоторых ситуациях крайне желательно, чтобы компилятор предупреждал или выдавал ошибку в коде, подобном reinterpret_cast<void*>(true), даже если этот код, по-видимому, является допустимым C ++. Например, это помогает в портировании на 64-битные платформы.

Преобразование 64-битного указателя в целочисленный тип, который меньше указателя (например, int или bool), часто является ошибкой: вы усекаете значение указателя. Кроме того, спецификация C ++, похоже, не гарантирует, что вы можете напрямую привести указатель к меньшему целочисленному типу (выделение добавлено):

5.2.10.4. Указатель может быть явно преобразован в любой целочисленный тип , достаточно большой, чтобы удерживать его . Функция отображения определяется реализацией.

Аналогично, преобразование меньшего целочисленного типа в 64-битный указатель (как с reinterpret_cast<void*>(true)) также часто является ошибкой: компилятор должен заполнить верхние биты указателя чем-то; это заполнение нулями или расширение знака? Если вы не пишете низкоуровневый платформо-зависимый код для доступа к вводу-выводу в память или DMA, вы обычно вообще не хотите этого делать, если только вы не делаете что-то хакерское (например, вставляете логический указатель в указатель ). Но спецификация C ++, по-видимому, мало говорит об этом случае, кроме того, что она определяется реализацией (сноска опущена):

5.2.10.5. Значение целочисленного типа или типа перечисления может быть явно преобразовано в указатель. *

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

@ monjardin предложил reinterpret_cast<void*>(static_cast<int>(true)). Если источником ошибки было несоответствие между размером целого типа и размером указателя, то это будет работать на большинстве 32-битных платформ (где int и void* являются 32-битными), но не на большинстве 64-битных платформы (где int - 32 бита, а void* - 64 бита). В этом случае замена int в этом выражении на целочисленный тип размера указателя, такой как uintptr_t или DWORD_PTR (в Windows), должна работать, поскольку разрешены преобразования между bool и целыми числами размера указателя, и поэтому преобразования между целыми числами и указателями размером с указатель.

Более поздние версии GCC имеют следующие опции подавления предупреждений , но не для C ++ :

-Wno-int-to-pointer-cast (только C и Objective-C)
Подавить предупреждения от приведения к типу указателя целого числа другого размера.

-Wno-pointer-to-int-cast (только C и Objective-C)
Подавить предупреждения от приведений из указателя на целочисленный тип другого размера.

0 голосов
/ 03 марта 2009

Попробуйте более новую версию вашего компилятора. Я только что проверил, и этот каст работает как минимум на gcc 4.1 и выше. Я точно не знаю, как версии gcc отображаются на версии mingw.

0 голосов
/ 03 марта 2009

Сбой, потому что приведение не имеет смысла - вы берете логическое значение истина / ложь и просите компилятор интерпретировать это как указатель, который в прямом смысле является местом памяти. Эти двое даже не связаны между собой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...