许多样式指南(例如Google建议使用int
索引数组时作为默认整数使用).随着64位平台的兴起,大多数时候a int
只有32位,这不是平台的自然宽度.因此,除了简单的说法,我认为没有理由保持这种选择.我们清楚地看到编译以下代码的位置:
double get(const double* p, int k) {
return p[k];
}
Run Code Online (Sandbox Code Playgroud)
被编译成
movslq %esi, %rsi
vmovsd (%rdi,%rsi,8), %xmm0
ret
Run Code Online (Sandbox Code Playgroud)
其中第一条指令将32位整数提升为64位整数.
如果代码转换成
double get(const double* p, std::ptrdiff_t k) {
return p[k];
}
Run Code Online (Sandbox Code Playgroud)
生成的程序集现在
vmovsd (%rdi,%rsi,8), %xmm0
ret
Run Code Online (Sandbox Code Playgroud)
这清楚地表明,CPU感觉更在家std::ptrdiff_t
比使用int
.许多C++用户已经迁移到了std::size_t
,但我不想使用无符号整数,除非我真的需要模数2^n
行为.
在大多数情况下,使用int
不会损害性能,因为未定义的行为或有符号整数溢出允许编译器在内部将任何内容int
提升为std::ptrdiff_t
处理索引的in循环,但我们从上面清楚地看到编译器不会感到宾至如归int
.此外,std::ptrdiff_t
在64位平台上使用会使溢出不太可能发生,因为当我们看到越来越多的人被int
溢出困住时,他们必须处理大于2^31 - 1
现在变得非常普遍的整数.
从我所看到的,这使得唯一int
脱颖而出似乎是文字,如事实5
是int
,但我不认为它会引起任何问题,如果我们移动到std::ptrdiff_t
一个默认的整数.
我即将成为std::ptrdiff_t
我小公司编写的所有代码的事实上的标准整数.这有什么理由可能是一个糟糕的选择吗?
PS:我同意这个名字 …
编译:
#include <iostream>
int main()
{
for (int i = 0; i < 4; ++i)
std::cout << i*1000000000 << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
并gcc
产生以下警告:
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
std::cout << i*1000000000 << std::endl;
^
Run Code Online (Sandbox Code Playgroud)
我知道有一个有符号的整数溢出.
我不能得到的是为什么i
价值被溢出操作打破了?
我已经阅读了为什么x86上的整数溢出与GCC导致无限循环的答案?,但我仍然不清楚为什么会发生这种情况 - 我认为"未定义"意味着"任何事情都可能发生",但这种特定行为的根本原因是什么?
编译: gcc (4.8)
以下代码进入GCC的无限循环:
#include <iostream>
using namespace std;
int main(){
int i = 0x10000000;
int c = 0;
do{
c++;
i += i;
cout << i << endl;
}while (i > 0);
cout << c << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
所以这是交易:有符号整数溢出在技术上是未定义的行为.但是x86上的GCC使用x86整数指令实现整数运算 - 它包含溢出.
因此,我本来期望它包装溢出 - 尽管事实上它是未定义的行为.但事实显然并非如此.那么我错过了什么?
我使用以下方法编译:
~/Desktop$ g++ main.cpp -O2
Run Code Online (Sandbox Code Playgroud)
GCC输出:
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
0
0
0
... (infinite loop)
Run Code Online (Sandbox Code Playgroud)
禁用优化后,没有无限循环且输出正确.Visual Studio也正确编译它并给出以下结果:
正确的输出:
~/Desktop$ g++ main.cpp
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
3
Run Code Online (Sandbox Code Playgroud)
以下是一些其他变体:
i *= 2; // Also …
Run Code Online (Sandbox Code Playgroud) 我想知道以下代码的使用
int result = 0;
int factor = 1;
for (...) {
result = ...
factor *= 10;
}
return result;
Run Code Online (Sandbox Code Playgroud)
如果循环是随着n
时间反复进行的,则将factor
其乘以10
精确的n
时间。但是,factor
仅在乘以10
总n-1
次数后才使用。如果我们假设factor
除了在循环的最后一次迭代之外永远不会溢出,而是可能在循环的最后一次迭代中溢出,那么这样的代码是否可以接受?在这种情况下,factor
证明溢出后永远不会使用的值。
我正在就是否应接受此类代码进行辩论。可以将乘法放在if语句中,并且在可能溢出时,不对循环的最后一次迭代进行乘法。缺点是它会使代码混乱,并添加了一个不必要的分支,需要在所有先前的循环迭代中进行检查。我还可以减少循环迭代一次,并在循环之后复制一次循环主体,这又使代码复杂化。
有问题的实际代码在一个紧密的内部循环中使用,该循环在实时图形应用程序中消耗大量的总CPU时间。
具体参考:https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p = 633 /
我是一名新的C++程序员,我目前正在学习未定义的行为及其对程序的影响.我特意链接到上面的博客,该博客说当发生未定义的行为时,任何事情都可能发生.
它特别提到了几次,当发生未定义的行为时,编译器可以允许任何事情发生.
具体是什么导致这种情况发生,为什么会发生?
我的应用程序评估用户指定的一些整数表达式.我想检测所有潜在的错误并报告它们.
所有计算都在int64_t
(签名)完成.式可以包括几乎所有的C++二进制运算符(+
,-
,*
,/
,%
,|
,||
,&
,&&
,和六比较运算符)和整数(可能是负数).
问题是:在评估可能使我的程序终止的表达式时可能发生什么错误?我想出了其中两个:
std::numeric_limits<int64_t>::min()
-1.也可能出现有符号整数溢出,但是,据我所知,在这样的设置中它不能对大多数CPU做任何有害的事情,所以我们忽略它.
我无法绕过这个.
当第4行看起来相同时
,为什么这两个函数会产生截然不同的结果
呢?
版本I
int factorial(int val) // input=5; output=120
{
if (val != 0)
return factorial(val - 1) * val;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
版本II
int factorial(int val) // input=5; output=0
{
if (val != 0)
return factorial(--val) * val;
return 1;
}
Run Code Online (Sandbox Code Playgroud)