Форум программистов, компьютерный форум, киберфорум
el_programmer
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
PVS-Studio - это инструмент для выявления ошибок в исходном коде программ, написанных на языках С, C++ и C#.

PVS-Studio выполняет статический анализ кода и генерирует отчёт, помогающий программисту находить и устранять ошибки. PVS-Studio выполняет широкий спектр проверок кода, но наиболее силён в поисках опечаток и последствий неудачного Copy-Paste. Показательные примеры таких ошибок: V501, V517, V522, V523, V3001.

Анализатор ориентирован на разработчиков, использующих среду Visual Studio, и может в фоновом режиме выполнять анализ измененных файлов после их компиляции. В идеале ошибки будут обнаружены и исправлены ещё до попадания в репозиторий. Однако ничто не мешает использовать анализатор для проверки всего решения целиком или для встраивания в системы непрерывной интеграции. Эти и иные способы использования анализатора описаны в документации.

О преобразовании типов в арифметических выражениях в C++ и C#

Запись от el_programmer размещена 29.03.2016 в 12:43
Показов 2480 Комментарии 1

Автор: Илья Иванов



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

Возможно у вас были случаи, когда тип арифметического выражения оказывался не таким как вы предполагали? Насколько хорошо вы знаете стандарт языка? Предлагаю проверить себя, заменив auto и var на правильный тип в этих выражениях и заодно вычислить результат:

C++ (будет считать, что используется модель данных LP64):

C++
1
2
3
4
5
6
7
8
9
10
11
12
void Test()
{
    unsigned char c1 = std::numeric_limits<unsigned char>::max();
    unsigned char c2 = std::numeric_limits<unsigned char>::max();
    int i1 = std::numeric_limits<int>::max();
    int i2 = std::numeric_limits<int>::max();
    unsigned int u1 = std::numeric_limits<unsigned int>::max();
 
    auto x = c1 + c2;
    auto y = i1 + i2;
    auto z = i1 + u1;
}
C#:

C#
1
2
3
4
5
6
7
8
9
10
11
12
void Test()
{
    byte b1 = byte.MaxValue;
    byte b2 = byte.MaxValue;
    int i1 = int.MaxValue;
    int i2 = int.MaxValue;
    uint u1 = uint.MaxValue;
 
    var x = b1 + b2;
    var y = i1 + i2;
    var z = i1 + u1;
}
Ответ ниже

С++ (LP64):

C++
1
2
3
    int x = c1 + c2;          // = 510
    int y = i1 + i2;          // = -2
    unsigned int z = i1 + u1; // = 2147483646
C#:

C#
1
2
3
    int x = b1 + b2;          // = 510
    int y = i1 + i2;          // = -2
    long z = i1 + u1;         // = 6442450942
Из этого теста, а если точнее, из стандартов языка С++ и C# следует:

1. Вычисление x. В арифметическом выражении все переменные, значения которых представимы типом int, будут преобразованы к типу int. Поэтому при сложении двух переменных типа char, unsigned char, short int, unsigned short int в C++ или переменных типа byte, sbyte, short, ushort в C# результат будет иметь тип int и переполнения не произойдёт. В наших примерах переменная x примет значение 510.

2. Вычисление y. Если оба аргумента имеют тип int дальнейшего расширения типов происходить уже не будет и здесь уже возможно переполнение. В C++ это неопределённое поведение. В C# по умолчанию в случае переполнения приложение продолжит работу. Используя ключевое слово checked или флаг компилятора /checked можно изменить поведение приложения чтобы в случае переполнения бросался OverflowException. В нашем тесте переменная y примет значение -2 и в C++ и в C#. Хотя ещё раз повторю, что в С++ мы имеем неопределённое поведение, результом которого может быть что угодно, например в y может быть записано число 100500 или произойдёт переполнение стека.

3. Вычисление z. Если один из аргументов имеет тип int, а другой unsigned intв C++ или uint в C#, то здесь стандарты двух языков написаны по-разному! В С++ оба аргумента будут преобразованы к типу unsigned int, кстати здесь уже не будет неопределённого поведения при переполнении. В C# оба аргумента будут преобразованы к типу long и переполнения не произойдёт ни при каких условиях. Поэтому мы и получили в наших программах на разных языках, разные значения для переменной z.

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

Пример на С++:

C++
1
2
3
4
5
6
7
8
9
10
11
typedef unsigned int    Ipp32u;
typedef signed int      Ipp32s;
 
Ipp32u m_iCurrMBIndex;
 
VC1EncoderMBInfo* VC1EncoderMBs::GetPevMBInfo(Ipp32s x, Ipp32s y)
{
    Ipp32s row = (y > 0) ? m_iPrevRowIndex : m_iCurrRowIndex;
    return ((m_iCurrMBIndex - x < 0 || row < 0)
        ? 0 : &m_MBInfo[row][m_iCurrMBIndex - x]);
}
Это пример кода из проекта IPP Samples. При сравнении результата выражения с нулём нужно помнить о том что int может быть преобразован в unsigned int, а long - в unsigned long. В нашем случае выражение m_iCurrMBIndex - x будет иметь тип unsigned int, и поэтому оно всегда неотрицательно, о чём сообщит PVS-Studio: V547 Expression 'm_iCurrMBIndex - x < 0' is always false. Unsigned type value is never < 0.

Пример на C#:

C#
1
2
3
4
5
6
7
8
9
10
public int Next(int minValue, int maxValue)
{
    long num = maxValue - minValue;
    if (num <= 0x7fffffffL)
    {
        return (((int)(this.Sample() * num)) + minValue);
    }
    return (((int)((long)(this.GetSampleForLargeRange() * num)))
        + minValue);
}
Это пример из проекта SpaceEngineers. В C# нужно помнить о том, что при сложении двух переменных типа int расширения типа до long не произойдёт в отличие от сложения переменной типа int и переменной типа uint. Поэтому здесь в переменную num будет записано значение типа int, которое всегда удовлетворяет условию num <= 0x7fffffffL. PVS-Studio знает об этом и выдаёт сообщение V3022 Expression 'num <= 0x7fffffffL' is always true.

Хорошо, когда знаешь стандарт и не допускаешь подобные ошибки, но на практике постоянно помнить все тонкости языка сложно, а в случае с C++ вообще нереально. Поэтому полезно пользоваться статическими анализаторами, например, PVS-Studio.


Дополнительные ссылки
  1. Преобразование типов в арифметических выражениях в C++.
  2. Преобразование типов в арифметических выражениях в C#.
Миниатюры
Нажмите на изображение для увеличения
Название: image1.png
Просмотров: 840
Размер:	38.3 Кб
ID:	3714  
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 1
Комментарии
  1. Старый комментарий
    Аватар для Avazart
    C++
    1
    
    auto x = c1 + c2;
    Мое личное мнение так писать не стоит, изрядное лентяйство.
    Запись от Avazart размещена 30.03.2016 в 22:11 Avazart вне форума
 
Новые блоги и статьи
20. Мат мед. Абсентеизм как отдельный тип простоя
anaschu 29.05.2026
Апдейт модели: исправленные баги, абсентеизм и новые механизмы Продолжаю развивать ранее описанную модель рабочего коллектива на AnyLogic. За последние несколько дней был проведён серьёзный. . .
19. здоровье, усталость и психотип работника влияют на производительность предприятия, и наоборот, производительность на здоровье, усталось и психотип
anaschu 28.05.2026
Дискретно-событийная модель рабочего коллектива на AnyLogic: здоровье, выгорание, психотипы и микростимуляция Привет, коллеги. Хочу поделиться итогами нескольких недель работы над симуляционной. . .
"Прокси" для последовательного порта
Eddy_Em 28.05.2026
Эту штуку написал я достаточно давно. Но сейчас вот понадобилось настроить датчик грозы, но при этом не отключать его от "метеодемона". Соответственно, надо запустить этот "прокси": метеодемон будет. . .
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru