Как выполнить приведение из bool в void*?
-
03-07-2019 - |
Вопрос
Я пытаюсь создать cairomm для gtkmm в Windows, используя mingw.Компиляция прерывается при вызове функции, у которой есть параметр, который выполняет переинтерпретацию bool в void*.
cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS, reinterpret_cast<void*>(true), NULL);
Именно здесь код прерывается, и причина в "недопустимом переинтерпретировании из bool в void *".Почему это происходит, и как я могу изменить эту строку, чтобы заставить ее скомпилироваться?Нужна помощь
Решение
Я вижу, что это пользовательские данные, и у вас есть контроль над тем, что делается со значением, сначала приведите bool к int: reinterpret_cast<void *> (static_cast<int> (true))
.Выполнение этого имеет смысл в том смысле, что параметр void * заменяет шаблонные функции в этой библиотеке ANSI-C.Все, что вам нужно, - это значение true / false.Таким образом, не должно быть никакой опасности во временном кодировании этого объекта как указателя, если он хорошо документирован как таковой.Действительно, тебе было бы лучше покончить с этим: reinterpret_cast<void *> (1)
или reinterpret_cast<void *> (+true)
.
Другие советы
Похоже, это должно сработать, согласно стандарту.В разделе 3.9.1-7 говорится, что bool является целочисленным типом, а в разделе 5.2.10-5 говорится, что значение целочисленного типа может быть явно преобразовано в указатель с помощью reinterpret_cast .Похоже, что ваш компилятор не полностью стандартен.
Не могли бы вы обойтись без изменения значения "true" на 1?Преобразование между целыми числами и типами указателей - старая и порочная традиция в C и, следовательно, в C ++, и было бы удивительно найти компилятор, который бы этого не делал.
Или, если вам действительно нужно это сделать, попробуйте (void *)true.Затем вымойте руки.
reinterpret_cast - это плохая идея.Расскажите нам подробнее о проблеме, которую вы пытаетесь решить, и, возможно, мы найдем решение, не прибегая к переосмыслению.Почему вы хотите преобразовать bool в void *?
Единственный компилятор, который у меня есть, который жалуется на это, - GCC (MinGW с GCC 3.4.5) - и я не уверен, почему.В стандарте, по-видимому, четко указано, что это разрешено:
3.9.1 Основные типы
...
Типы bool, char, wchar_t и целочисленные типы со знаком и без знака в совокупности называются целочисленными типами.
5.2.10 Переосмыслить приведение:
...
Значение целочисленного типа или типа перечисления может быть явно преобразовано в указатель.
Это сказало, обходной путь монжардена использования reinterpret_cast<void *> (static_cast<int> (true))
или reinterpret_cast<void *> (1)
есть разумные обходные пути.
Это не удается, потому что приведение не имеет смысла - вы принимаете логическое значение true / false и просите компилятор интерпретировать это как указатель, который, грубо говоря, является ячейкой памяти.Эти двое даже отдаленно не связаны.
Попробуйте более новую версию вашего компилятора.Я только что протестировал, и это приведение работает, по крайней мере, на gcc 4.1 и выше.Однако я не знаю точно, как версии gcc соотносятся с версиями mingw.
В некоторых ситуациях крайне желательно, чтобы компилятор предупреждал или выдавал ошибку в коде типа 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-в-указатель (только для C и Objective-C)
Подавлять предупреждения при приведении к типу указателя целого числа другого размера.-Wno-указатель-на-int-приведение (только для C и Objective-C)
Подавлять предупреждения при приведении указателя на целочисленный тип другого размера.