我正在尝试编写一个C++模板函数,它将在不同整数类型之间的转换中抛出整数溢出的运行时异常,具有不同的宽度,以及可能的有符号/无符号不匹配.出于这些目的,我不关心从浮点类型转换为整数类型,也不关心其他对象到对象的转换.我想这样做而不必写很多特殊的案例代码.这就是我目前拥有的:
template< typename T, typename R > void safe_cast( const T& source, R& result )
{
// get the maximum safe value of type R
R rMax = (R) ~0;
if ( rMax < 0 ) // R is a signed type
{
// assume that we're on an 8-bit twos-compliment machine
rMax = ~( 0x80 << ( ( sizeof( R ) - 1 ) * 8 ) );
}
if ( ( source & rMax ) != source ) …Run Code Online (Sandbox Code Playgroud) 不,这不是如何检测整数溢出的重复?.问题是一样的,但问题是不同的.
gcc编译器可以优化掉溢出检查(使用-O2),例如:
int a, b;
b = abs(a); // will overflow if a = 0x80000000
if (b < 0) printf("overflow"); // optimized away
Run Code Online (Sandbox Code Playgroud)
gcc人认为这不是一个错误.根据C标准,溢出是未定义的行为,它允许编译器执行任何操作.显然,任何事情都包括假设溢出永远不会发生.不幸的是,这允许编译器优化掉溢出检查.
最近的CERT文件中描述了检查溢出的安全方法.本文建议在添加两个整数之前执行类似的操作:
if ( ((si1^si2) | (((si1^(~(si1^si2) & INT_MIN)) + si2)^si2)) >= 0) {
/* handle error condition */
} else {
sum = si1 + si2;
}
Run Code Online (Sandbox Code Playgroud)
显然,当你想确保结果有效时,你必须在一系列计算中的每个+, - ,*,/和其他操作之前做这样的事情.例如,如果要确保数组索引不受限制.这太麻烦了,几乎没有人这样做.至少我从未见过一个系统地执行此操作的C/C++程序.
现在,这是一个根本问题:
在访问阵列之前检查数组索引很有用,但不可靠.
使用CERT方法检查一系列计算中的每个操作都是可靠但无用的.
结论:在C/C++中没有有用且可靠的方法来检查溢出!
我拒绝相信这是在编写标准时的意图.
我知道有一些命令行选项可以解决问题,但这并没有改变我们对标准或其当前解释存在根本问题的事实.
现在我的问题是:gcc的人服用的"未定义行为"的解释时,它允许他们优化掉溢出检查,否则过犹不及是C/C++标准坏了吗?
补充说明: 对不起,您可能误解了我的问题.我不是问如何解决这个问题 - 这已经在其他地方得到了回答.我在问一个关于C标准的更基本的问题.如果没有有用且可靠的检查溢出的方法,那么语言本身就是可疑的.例如,如果我使用边界检查创建一个安全的数组类,那么我应该是安全的,但是如果边界检查可以被优化掉,我就不会这样做.
如果标准允许这样做,则标准需要修订或标准需求修订的解释.
补充说明2: 这里的人似乎不愿意讨论"未定义行为"的可疑概念.C99标准列出了191种不同的未定义行为( …
我有一个8个字符string代表一个十六进制数字,我需要将其转换为int.这种转换必须保留字符串"80000000"和更高的位模式,即这些数字应该是负数.不幸的是,天真的解决方案:
int hex_str_to_int(const string hexStr)
{
stringstream strm;
strm << hex << hexStr;
unsigned int val = 0;
strm >> val;
return static_cast<int>(val);
}
Run Code Online (Sandbox Code Playgroud)
如果val > MAX_INT(返回值为0),则对我的编译器不起作用.更改val的类型int也会导致较大的数字为0.我在SO上尝试了几种不同的解决方案,但尚未成功.
这就是我所知道的:
sizeof(int) 我的代码将在每个架构上运行至少4个.long到int的结果INT_MAX,当值过大.这是非常难以正确地做到,或者至少它已经适合我.有谁知道这个便携式解决方案?
更新:
更改static_cast为reinterpret_cast导致编译器错误.评论促使我尝试C风格的演员:return (int)val在上面的代码中,它工作. 在这台机器上. 在其他架构上,这仍然是安全的吗?
对于C(short,int,long等)中的"标准"有符号整数类型的所有操作,如果它们产生超出[TYPE_MIN,TYPE_MAX]间隔的结果(其中TYPE_MIN,TYPE_MAX是最小值和最大整数值),则表现出未定义的行为可以通过特定整数类型存储的.
但是,根据C99标准,所有intN_t类型都需要具有二进制补码表示:
7.8.11.1精确宽度整数类型
1. typedef名称intN_t指定有符号整数类型,其宽度为N,无填充位和二进制补码表示.因此,int8_t表示具有正好8位宽度的有符号整数类型.
这是否意味着intN_tC99 中的类型在整数溢出的情况下表现出良好定义的行为?例如,这段代码定义明确吗?
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
printf("Minimum 32-bit representable number: %" PRId32 "\n", INT32_MAX + 1);
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我想!1000在clojure中计算,如何在不获得整数溢出异常的情况下执行此操作?
我的阶乘代码现在是:(reduce * (range 1 1001)).
在执行数学运算之后,比如乘以两个整数,是否可以使用C++访问CPU中的溢出标志寄存器?如果没有其他快速方法来检查溢出?
自从我开始使用eclipse作为项目euler以来,我注意到大数字有时会变成看似随机的负数.我想这与传递类型的boudry有关.
如果你能向我解释这些负数是如何产生的,以及它背后的逻辑是什么,我将很高兴.另外,我怎样才能避免它们(最好不要使用BigInteger类).丹科!=)
如果我在立即窗口中键入以下内容,则会出现运行时错误"6":溢出.
MsgBox 24 * 60 * 60
Run Code Online (Sandbox Code Playgroud)
为什么是这样?
这也失败了:
Dim giveTime As Long
giveTime = 24 * 60 * 60
Run Code Online (Sandbox Code Playgroud)
为什么是这样?giveTime声明为Long类型,因此24×60×60 = 86400应该适合.
我一直在考虑整数(类型int)溢出,并且我发现分裂可能溢出.
示例:在我当前的平台上,我有
INT_MIN == -INT_MAX - 1
Run Code Online (Sandbox Code Playgroud)
因此
INT_MIN < -INT_MAX
Run Code Online (Sandbox Code Playgroud)
因此
INT_MIN / -1 > -INT_MAX / -1
Run Code Online (Sandbox Code Playgroud)
因此
INT_MIN / -1 > INT_MAX.
Run Code Online (Sandbox Code Playgroud)
因此,除法(INT_MIN/-1)确实溢出.
所以,我有两个问题:
可以编写什么(跨平台)C代码以防止除法溢出(对于类型(带符号)int)?
什么保证(在C或C++标准中)可能有助于设计代码?
例如,如果标准保证我们有
INT_MIN == -INT_MAX - 1
Run Code Online (Sandbox Code Playgroud)
要么
INT_MIN == -INT_MAX,
Run Code Online (Sandbox Code Playgroud)
然后出现以下代码以防止溢出.
#include <limits.h>
/*
Try to divide integer op1 by op2.
Return
0 (success) or
1 (possibly overflow prevented).
In case of success, write the quotient to res.
*/
int safe_int_div(int * res, int op1, int op2) { …Run Code Online (Sandbox Code Playgroud) 我正在编写一个计算量很大的程序,在调试模式下运行起来非常慢.
我的程序也受到整数溢出的困扰,因为我正在从u8数组中读取数据并u8通过类型推断将扩展类型扩展到意外的位置,而Rust更喜欢溢出而不是将整数提升为更大的类型.
在发布模式下构建会禁用溢出检查:
cargo run --release
Run Code Online (Sandbox Code Playgroud)
如何通过优化和运行时溢出检查来构建Rust可执行文件?