Battary 7 / 6 / 1 Регистрация: 29.10.2016 Сообщений: 175 |
||||||||||||
1 |
||||||||||||
Арифметическое переполнение27.01.2020, 18:33. Показов 27493. Ответов 4 Метки нет (Все метки)
Доброго всем времени суток! Никак не могу решить проблему с этим: Кликните здесь для просмотра всего текста
C26451 Арифметическое переполнение: использование оператора «-» на байтовом значении 4 и приведение результата к байтовому значению 8. Приведите значение к более широкому типу перед вызовом оператора «-«, чтобы избежать переполнения (io.2). Собственно почему? Я же прибавляю 4байтовый int (1) к 4байтовому j. Функция
Класс
Main
__________________
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
27.01.2020, 18:33 |
Ответы с готовыми решениями: Переполнение Переполнение void menu() Переполнение Exception переполнение 4 |
6574 / 4559 / 1843 Регистрация: 07.05.2019 Сообщений: 13,726 |
|
27.01.2020, 19:08 |
2 |
Я в курсе, что возвращаемое значение метода .size() не int, а size_t, но ни замена int на size_t в for, ни приведение к int не решают эту проблему. Как можно решать это? Используй size_t в обоих циклах, для i и для j. Зачем тебе там int?
0 |
7 / 6 / 1 Регистрация: 29.10.2016 Сообщений: 175 |
|
27.01.2020, 20:07 [ТС] |
3 |
Используй size_t в обоих циклах, для i и для j. Зачем тебе там int? Я пробовал, ошибка не уходит. А int там нужен, потому что массив не больше 1000.
0 |
6574 / 4559 / 1843 Регистрация: 07.05.2019 Сообщений: 13,726 |
|
27.01.2020, 21:10 |
4 |
Сообщение было отмечено Battary как решение Решение
Я пробовал, ошибка не уходит. А int там нужен, потому что массив не больше 1000. Во-первых, это не ошибка, а предупреждение, в принципе можно забить.
0 |
большой ДЕН 1 / 1 / 0 Регистрация: 01.05.2017 Сообщений: 144 |
||||
26.09.2020, 19:15 |
5 |
|||
Привет.
Выражение «(k — 1)» подчеркнутос предупреждением «c26451 арифметическое переполнение использование оператора «-» на байтовом значении 4 и приведение результата к байтовому значению 8″
0 |
IT_Exp Эксперт 87844 / 49110 / 22898 Регистрация: 17.06.2006 Сообщений: 92,604 |
26.09.2020, 19:15 |
Помогаю со студенческими работами здесь Задача на переполнение Переполнение стека Переполнение double как отловить переполнение при расчетах double; double db =… Переполнение буфера int… Искать еще темы с ответами Или воспользуйтесь поиском по форуму: 5 |
In C++ (and pretty much any other C-like high level languages) arithmetic operations between 2 numbers produces a value of the same type if the original types are the same, and a value of the common type of the two if they’re different. Indeed multiplying two 32-bit numbers produces a 64-bit result but that’s not how C++ works
The arguments of the following arithmetic operators undergo implicit conversions for the purpose of obtaining the common real type, which is the type in which the calculation is performed:
- binary arithmetic *, /, %, +, —
- relational operators <, >, <=, >=, ==, !=
- binary bitwise arithmetic &, ^, |,
- the conditional operator ?:
https://en.cppreference.com/w/c/language/conversion
The full rule to obtain the common type can be read in the link above, or in the standard below
If m and n are int
s then their product is also an int. Hence there’s a warning in new int[m * n];
because the new operator receives a size_t
which is a 64-bit unsigned type on your platform. Same to new int[(long)m * n]
because the common type of long
and int
is long
(which is also a 32-bit type on Windows)
To get the full 64-bit product you need to cast at least one of the operands to a 64-bit type which is long long
in MSVC. That’s why the last line new int[(long long)m * n];
works. However you’ll get a warning related to conversion between signed and unsigned
From ISO/IEC 9899:201x C++ standard
6.3.1.8 Usual arithmetic conversions
Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions:
- First, if the corresponding real type of either operand is long double, the other operand is converted, without change of type domain, to a type whose
corresponding real type is long double.- Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose
corresponding real type is double.- Otherwise, if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose
corresponding real type is float.- Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
- If both operands have the same type, then no further conversion is needed.
Otherwise, if both operands have signed integer types or both have unsigned
integer types, the operand with the type of lesser integer conversion rank is
converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater or
equal to the rank of the type of the other operand, then the operand with
signed integer type is converted to the type of the operand with unsigned
integer type.- Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the
operand with signed integer type.- Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.
In C++ (and pretty much any other C-like high level languages) arithmetic operations between 2 numbers produces a value of the same type if the original types are the same, and a value of the common type of the two if they’re different. Indeed multiplying two 32-bit numbers produces a 64-bit result but that’s not how C++ works
The arguments of the following arithmetic operators undergo implicit conversions for the purpose of obtaining the common real type, which is the type in which the calculation is performed:
- binary arithmetic *, /, %, +, —
- relational operators <, >, <=, >=, ==, !=
- binary bitwise arithmetic &, ^, |,
- the conditional operator ?:
https://en.cppreference.com/w/c/language/conversion
The full rule to obtain the common type can be read in the link above, or in the standard below
If m and n are int
s then their product is also an int. Hence there’s a warning in new int[m * n];
because the new operator receives a size_t
which is a 64-bit unsigned type on your platform. Same to new int[(long)m * n]
because the common type of long
and int
is long
(which is also a 32-bit type on Windows)
To get the full 64-bit product you need to cast at least one of the operands to a 64-bit type which is long long
in MSVC. That’s why the last line new int[(long long)m * n];
works. However you’ll get a warning related to conversion between signed and unsigned
From ISO/IEC 9899:201x C++ standard
6.3.1.8 Usual arithmetic conversions
Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions:
- First, if the corresponding real type of either operand is long double, the other operand is converted, without change of type domain, to a type whose
corresponding real type is long double.- Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose
corresponding real type is double.- Otherwise, if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose
corresponding real type is float.- Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
- If both operands have the same type, then no further conversion is needed.
Otherwise, if both operands have signed integer types or both have unsigned
integer types, the operand with the type of lesser integer conversion rank is
converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater or
equal to the rank of the type of the other operand, then the operand with
signed integer type is converted to the type of the operand with unsigned
integer type.- Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the
operand with signed integer type.- Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.
Как устранить эти предупреждения?
// midiNote is a double as it is used in floating point equation
// v is int because that's informative that the function wants whole numbers
void setMidiNote(int v) { midiNote = v-48; }
Предупреждение C26451 Арифметическое переполнение: использование оператора ‘-‘ для 4-байтового значения и последующее приведение результата к 8-байтовому значению. Перед вызовом оператора ‘-‘ приведите значение к более широкому типу, чтобы избежать переполнения (io.2).
// input should be 0 to 10 integer, and dank will be odd integers only
// dank is a double, it is ultimately used in a floating point equation
void setDarkIntensity(int v) { dank = v * 2 + 1; }
Предупреждение C26451 Арифметическое переполнение: использование оператора ‘*’ для 4-байтового значения и последующее преобразование результата к 8-байтовому значению. Перед вызовом оператора ‘*’ приведите значение к более широкому типу, чтобы избежать переполнения (io.2).
Предупреждение C26451 Арифметическое переполнение: использование оператора ‘+’ для 4-байтового значения и последующее приведение результата к 8-байтовому значению. Приведите значение к более широкому типу перед вызовом оператора ‘+’, чтобы избежать переполнения (io.2).
7 ответов
Предупреждения говорят вам, что существует вероятность того, что ваши вычисления переполнят исходный (меньший) тип перед преобразованием в результат (больший) тип. В первом случае, если v
равно MIN_INT (-2 31 ), вычитание опустится, что приведет к неопределенному поведению (вероятно, большое положительное число), которое затем будет сохранено в midiNote
. Чтобы избежать предупреждения, сначала конвертируйте в более крупный тип:
midiNote = double(v) - 48;
Аналогично вашему второму примеру.
Хотя вы можете знать, что setMidiNote
не будет вызываться со значениями, которые будут иметь эту проблему, компилятор не знает и выдает это предупреждение, чтобы предупредить вас о возможности возникновения проблемы.
7
1201ProgramAlarm
5 Май 2019 в 22:58
Я считаю, что это ошибка VS2019. Он больше не отмечен в VS2022.
Например, это вызывает предупреждение
double test2(int n)
{
return 4.0 * (n - 1);
}
Но это не так
int test2a(int n)
{
return 4 * (n - 1);
}
Однако для последнего риск неопределенного поведения намного выше. Умножение на 4 значительно увеличивает риск UB, поскольку очень большой набор n даст UB. Как здорово? Что ж, есть только одно возможное значение n
из примерно 4 миллиардов возможных значений в первом примере, которое переполняется. Во втором есть около 3 миллиардов n
, которые могут быть переполнены / не заполнены. Почему? Потому что целочисленная арифметика была бы невозможна, если бы каждое выражение с большей сложностью, чем добавление 0 или умножение на 1, было помечено, потому что оно могло переполняться.
Вероятно, для такого высокого значения предупреждения будет предупреждена практически любая арифметическая операция с целыми числами.
Этот ответ показывает способ отключить это предупреждение в VS 2019 в редакторе набора правил анализа кода.
Предупреждение C26454: арифметическое переполнение: операция ‘-‘ дает отрицательный результат без знака во время компиляции (io.5)
Однако Microsoft, начиная с VS2022, больше не выдает предупреждение C26451 в виде волнистой линии для этого. И не отображается под -Wall. Видимо, они увидели свет.
19
doug
15 Дек 2021 в 06:56
Я решил проблему, посмотрев на Microsoft Docs, но вы также можете изменить свой переменная в тип long long
(я знаю, сверху). Это избавило меня от ошибок. Надеюсь, они скоро займутся этим.
3
KoalaZub
2 Янв 2020 в 16:30
Я избавился от предупреждения, изменив тип переменной на «unsigned __int64». Это то, что предлагает сообщество разработчиков Microsoft!
3
passionateProgrammer
2 Май 2020 в 19:57
Static_cast<>() является рекомендуемым решением. В книге, которую я сейчас читаю, большое внимание уделяется этому новому соглашению о приведении типов. Простое использование (v) считается стилем C.. (Согласно литературе). .Интересно.. сработает ли просто объявить v как auto. Похоже, Вектор что-то замышляет…
Недействительным setDarkIntensity (авто v) { сырой = v * 2 + 1; }
0
George Abraham
3 Авг 2022 в 20:03
Приведите тип данных, который вы хотите, как можно раньше, а затем используйте его полностью:
// midiNote is a double as it is used in floating point equation
// v is int because that's informative that the function wants whole numbers
void setMidiNote(int v) { midiNote = static_cast<double>(v) - 48.0; }
// input should be 0 to 10 integer, and dank will be odd integers only
// dank is a double, it is ultimately used in a floating point equation
void setDarkIntensity(int v) { dank = static_cast<double>(v) * 2.0 + 1.0; }
Раньше считалось, что операции с целыми числами выполняются намного быстрее, чем операции с плавающей запятой, но это уже не так для современных процессоров.
Использование 2.0
вместо 2
приводит к неявному приведению v
к double
, но явное приведение всегда более понятно.
Дополнительный совет: рассмотрите возможность проверки любых предположений в отладочных сборках. Это поможет избежать нарушения этих предположений при изменении кода в будущем. Что-то типа:
// input should be 0 to 10 integer, and dank will be odd integers only
// dank is a double, it is ultimately used in a floating point equation
void setDarkIntensity(int v)
{
assert(v >= 0 && v <= 10);
dank = static_cast<double>(v) * 2.0 + 1.0;
}
Дополнительный совет 2: если эти функции не являются частью класса, я бы назвал их inline
, чтобы у оптимизатора было больше шансов справиться с этими простыми функциями. Если они являются частью определения класса, то это уже сделано неявно.
0
Darrin Cullop
5 Авг 2022 в 20:00
title | description | ms.date | f1_keywords | helpviewer_keywords | ||
---|---|---|---|---|---|---|
Warning C26451 |
Describes the causes of MSVC code analysis warning C26451, and shows how to fix it. |
07/15/2020 |
|
C26451 |
Warning C26451
Arithmetic overflow: Using operator ‘operator‘ on a size-a byte value and then casting the result to a size-b byte value. Cast the value to the wider type before calling operator ‘operator‘ to avoid overflow (io.2)
This warning indicates incorrect behavior that results from integral promotion rules and types larger than the ones in which arithmetic is typically performed.
Remarks
Code analysis detects when an integral value gets shifted left, multiplied, added, or subtracted, and the result gets cast to a wider integral type. If the operation overflows the narrower integral type, then data is lost. You can prevent this loss by casting the value to a wider type before the arithmetic operation.
Code analysis name: RESULT_OF_ARITHMETIC_OPERATION_CAST_TO_LARGER_SIZE
Example 1
The following code generates this warning:
void leftshift(int i) noexcept { unsigned __int64 x; x = i << 31; // C26451 reported here // code }
To correct this warning, use the following code:
void leftshift(int i) noexcept { unsigned __int64 x; x = static_cast<unsigned __int64>(i) << 31; // OK // code }
Example 2
void somefunc(__int64 /* y */) noexcept {} void callsomefunc(int x) noexcept { somefunc(x * 2); // C26451 reported here }
To correct this warning, use the following code:
void callsomefunc(int x) noexcept { somefunc(static_cast<__int64>(x) * 2); // OK }
Example 3
__int64 add(int x) noexcept { constexpr auto value = 2; return x += value; // C26451 reported here }
To correct this warning, use the following code:
__int64 add(int x) noexcept { constexpr auto value = 2; const __int64 y = static_cast<__int64>(x) + value; // OK return y; }
See also
- ES.103: Don’t overflow
title | description | ms.date | f1_keywords | helpviewer_keywords | ||
---|---|---|---|---|---|---|
Warning C26451 |
Describes the causes of MSVC code analysis warning C26451, and shows how to fix it. |
07/15/2020 |
|
C26451 |
Warning C26451
Arithmetic overflow: Using operator ‘operator‘ on a size-a byte value and then casting the result to a size-b byte value. Cast the value to the wider type before calling operator ‘operator‘ to avoid overflow (io.2)
This warning indicates incorrect behavior that results from integral promotion rules and types larger than the ones in which arithmetic is typically performed.
Remarks
Code analysis detects when an integral value gets shifted left, multiplied, added, or subtracted, and the result gets cast to a wider integral type. If the operation overflows the narrower integral type, then data is lost. You can prevent this loss by casting the value to a wider type before the arithmetic operation.
Code analysis name: RESULT_OF_ARITHMETIC_OPERATION_CAST_TO_LARGER_SIZE
Example 1
The following code generates this warning:
void leftshift(int i) noexcept { unsigned __int64 x; x = i << 31; // C26451 reported here // code }
To correct this warning, use the following code:
void leftshift(int i) noexcept { unsigned __int64 x; x = static_cast<unsigned __int64>(i) << 31; // OK // code }
Example 2
void somefunc(__int64 /* y */) noexcept {} void callsomefunc(int x) noexcept { somefunc(x * 2); // C26451 reported here }
To correct this warning, use the following code:
void callsomefunc(int x) noexcept { somefunc(static_cast<__int64>(x) * 2); // OK }
Example 3
__int64 add(int x) noexcept { constexpr auto value = 2; return x += value; // C26451 reported here }
To correct this warning, use the following code:
__int64 add(int x) noexcept { constexpr auto value = 2; const __int64 y = static_cast<__int64>(x) + value; // OK return y; }
See also
- ES.103: Don’t overflow