Предупреждения или ошибки для неявного преобразования примитивов C++

Я провел серьезный рефакторинг некоторого кода C++ и обнаружил множество ошибок, возникающих из-за неявных преобразований, о которых я не знаю.

Пример

struct A *a();

bool b() {
    return a();
}

void c() {
    int64_t const d(b());
}

Проблемы

  1. В b тип возвращаемого значения a автоматически преобразуется в bool.
  2. В c значение, возвращенное из b, автоматически повышается до int64_t.

Вопрос

Как я могу получать предупреждения или ошибки для неявного преобразования между примитивными типами?

Примечание

  1. Использование -Wconversion, по-видимому, приводит только к нескольким произвольным преобразованиям, не связанным с приведенным выше примером.
  2. BOOST_STRONG_TYPEDEF не подходит (мои типы должны быть POD, поскольку они используются в дисковых структурах).
  3. C также представляет интерес, однако эта проблема относится к кодовой базе C++.

person Matt Joiner    schedule 18.12.2010    source источник
comment
Я не знаю, предупредит ли -Wextra об этом, но в целом, если вы хотите получить больше диагностики и найти больше сомнительных мест в своем коде, попробуйте собрать его на нескольких компиляторах с отключенными расширениями и включенными всеми предупреждениями. Например gcc, icc и clang. Вы, безусловно, найдете больше проблем.   -  person Öö Tiib    schedule 18.12.2010
comment
какую версию gcc вы используете?   -  person Raxvan    schedule 28.01.2014
comment
Оба приведения соответствуют стандарту, поэтому компилятор не должен предупреждать о них. Попробуйте статический анализатор кода. См. также комментарии к этому (к сожалению, закрытому) вопросу stackoverflow.com/questions/19306020/   -  person example    schedule 28.01.2014
comment
@Raxvan: Любая версия.   -  person Matt Joiner    schedule 29.01.2014


Ответы (6)


В языке программирования C++, 3-е издание, приложение C.6, а именно "Неявное преобразование типов", Бьерн Страуструп классифицирует конверсии как рекламные акции и конверсии: первые «сохраняют ценность» (ваш вариант 2), вторые — нет (вариант 1).

О преобразованиях он говорит следующее: «Фундаментальные типы могут быть преобразованы друг в друга ошеломляющим количеством способов. На мой взгляд, разрешено слишком много преобразований». и «Компилятор может предупредить о многих сомнительных преобразованиях. К счастью, многие компиляторы действительно это делают».

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

Предупреждения компилятора обычно не являются обязательными. Обычно в черновиках и окончательных документах ANSI C++ сообщается, что "исполнители должны выдавать предупреждение" там, где предложено: вы можете проверить это самостоятельно для получения дополнительной информации, если это необходимо.

EDITED: добавлено примечание С++ 11:

В Язык программирования C++, 4-е издание, приложение 3-го издания сообщается и расширяется как раздел 10.5, "Неявное преобразование типов" еще раз.

Поскольку предыдущие рассуждения остаются теми же, C++11 более точно определяет «сужающие преобразования» и добавляет нотацию {}-initializer (6.3.5), с которой усечения приводят к ошибке компиляции.

person Sigi    schedule 29.01.2014

Если вы используете gcc, пробовали ли вы -Wall -Wextra, в основном проверьте эту страницу
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Если это не GCC, опубликуйте сведения о компиляторе.

person Abhi    schedule 18.12.2010

Microsoft Visual C++ выдаст предупреждение о сужающем преобразовании из A* в bool.

См. предупреждение компилятора C4800

С другой стороны, продвижение не является «опасной» конверсией, потому что потерять данные невозможно.

РЕДАКТИРОВАТЬ: Демонстрация

C:\Users\Ben>copy con test.cpp
bool f( void ) { return new int(); }
^Z
        1 file(s) copied.

C:\Users\Ben>cl /c /W4 test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
test.cpp(1) : warning C4800: 'int *' : forcing value to bool 'true' or 'false' (
performance warning)
person Ben Voigt    schedule 18.12.2010
comment
Почти уверен, что это предупреждение относится только к int и друзьям, а не к указателям, поскольку они явно предназначены для проверки на NULL. - person Puppy; 19.12.2010
comment
@DeadMG: это не происходит в логическом контексте, таком как оператор if или while, только при фактическом создании переменной bool из значения. - person Ben Voigt; 19.12.2010
comment
Повышение от long до double обычно разрешено, и оно может потерять точность. - person Roland Illig; 02.06.2011

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

Вы уверены, что такой подход, как BOOST_STRONG_TYPEDEF, не сработает в вашей проблеме? Класс без виртуальных функций-членов и только с одним примитивным членом данных — это не что иное, как тип данных POD. Вы можете просто следовать тому же подходу и разрешать преобразование только в базовый примитивный тип; пример:

#include <iostream>
#include <stdexcept>

struct controlled_int {
  // allow creation from int
  controlled_int(int x) : value_(x) { };
  controlled_int& operator=(int x) { value_ = x; return *this; };
  // disallow assignment from bool; you might want to use BOOST_STATIC_ASSERT instead
  controlled_int& operator=(bool b) { throw std::logic_error("Invalid assignment of bool to controlled_int"); return *this; };

  // creation from bool shouldn't happen silently
  explicit controlled_int(bool b) : value_(b) { };

  // conversion to int is allowed
  operator int() { return value_; };

  // conversion to bool errors out; you might want to use BOOST_STATIC_ASSERT instead

  operator bool() { throw std::logic_error("Invalid conversion of controlled_int to bool"); };

  private:
    int value_;
};

int main()
{
  controlled_int a(42);

  // This errors out:
  // bool b = a;

  // This gives an error as well:
  //a = true;

  std::cout << "Size of controlled_int: " << sizeof(a) << std::endl;
  std::cout << "Size of int: " << sizeof(int) << std::endl;

  return 0;
}
person Riccardo Murri    schedule 18.12.2010
comment
Тот факт, что компилятор должен разрешить преобразование, не означает, что он будет делать это молча. Некоторые компиляторы ДЕЙСТВИТЕЛЬНО выдают предупреждения для преобразований, разрешенных стандартом, но опасных (т. е. сужающих преобразования различных видов). Например, я считаю, что MSVC++ выдает предупреждение о преобразовании из A* в bool< /а>. - person Ben Voigt; 19.12.2010

Вы можете использовать один из доступных инструментов статического анализа, такие программы, как clint или эквиваленты C++, или один из имеющихся в продаже инструментов. Многие из этих инструментов могут выявить проблемные неявные преобразования.

person Yttrill    schedule 18.12.2010

Напишите собственный плагин clang для диагностики ваших проблем. Мы делаем многое из этого в коде LibreOffice. Если вам нужно вдохновение, просмотрите наш источник на http://cgit.freedesktop.org/libreoffice/core/tree/compilerplugins/clang

person Noel Grandin    schedule 14.06.2015