在最近的家庭作业中,我被告知使用long变量来存储结果,因为它可能是一个很大的数字.
我决定检查它对我来说真的很重要,在我的系统上(intel core i5/64-bit windows 7/gnu gcc编译器)并发现以下代码:
printf("sizeof(char) => %d\n", sizeof(char));
printf("sizeof(short) => %d\n", sizeof(short));
printf("sizeof(short int) => %d\n", sizeof(short int));
printf("sizeof(int) => %d\n", sizeof(int));
printf("sizeof(long) => %d\n", sizeof(long));
printf("sizeof(long int) => %d\n", sizeof(long int));
printf("sizeof(long long) => %d\n", sizeof(long long));
printf("sizeof(long long int) => %d\n", sizeof(long long int));
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
sizeof(char) => 1
sizeof(short) => 2
sizeof(short int) => 2
sizeof(int) => 4
sizeof(long) => 4
sizeof(long int) => 4
sizeof(long long) => 8
sizeof(long long int) => …Run Code Online (Sandbox Code Playgroud) 此声明在g ++ -pedantic -Wall(版本4.6.3)中编译时没有警告:
std::size_t foo = -42;
Run Code Online (Sandbox Code Playgroud)
不太明显的伪造是使用size_t参数声明一个函数,并使用负值调用它.这样的功能可以防止无意中的负面论证(看起来像是无数的庸俗,遵守§4.7/ 2)吗?
答案不完整:
只需将size_t更改为(signed)long就会丢弃size_t的语义和其他优点.
将其更改为ssize_t仅仅是POSIX,而不是标准.
将它改为ptrdiff_t是脆弱的,有时会破坏.
测试巨大的值(高位设置等)是任意的.
假设我的程序中有一个非常性能关键的循环,我需要检查一个点是否在矩形内,但我知道在编译时下限始终为0,如下所示: (x >= 0 && y >= 0 && x < width && y < height)
我可以消除前两个比较的类型双关x和y的无符号整数(例如喜欢的东西reinterpret_cast<>()或union用C++),因为符号位将保证任何负数会变成一个unsigned int足够大的失败边界检查?如果是这样,您将如何用C++或其他语言实现它?这样做可以获得任何性能提升吗?
当我在工作时,string::npos我注意到了一些东西,我在网上找不到任何解释.
(string::npos == ULONG_MAX)
Run Code Online (Sandbox Code Playgroud)
和
(string::npos == -1)
Run Code Online (Sandbox Code Playgroud)
是真的.
所以我尝试了这个:
(18446744073709551615 == -1)
Run Code Online (Sandbox Code Playgroud)
这也是事实.
怎么可能?是因为二元对话吗?
我遇到过执行以下转换的代码:
static_cast<unsigned long>(-1)
据我所知,C++标准定义了将有符号整数值转换为无符号整数类型时会发生什么(请参阅:如果我将一个负值分配给无符号变量,会发生什么?).
我在上面的代码中所关心的是源和目标类型可能是不同的大小,以及这是否会对结果产生影响.编译器会在转换之前扩大源值类型吗?它会转换为相同大小的无符号整数然后放大吗?或许还有其他什么?
用代码澄清,
int nInt = -1;
long nLong = -1; // assume sizeof(long) > sizeof(int)
unsigned long res1 = static_cast<unsigned long>(nInt)
unsigned long res2 = static_cast<unsigned long>(nLong);
assert(res1 == res2); // ???
Run Code Online (Sandbox Code Playgroud)
基本上,我应该担心像编写代码一样
static_cast<unsigned long>(-1L)
Run Code Online (Sandbox Code Playgroud)
过度
static_cast<unsigned long>(-1)
Run Code Online (Sandbox Code Playgroud) 假设我有两个size_t变量,我需要将它们相乘并得到结果size_t.
size_t first = ...;
size_t second = ...;
size_t result = first * second;
Run Code Online (Sandbox Code Playgroud)
它们可能会溢出,所以我需要检查一下.
"干净"的方法是先使用除法检查乘法是否可行:
if( second != 0 && first > ((size_t)-1) / second ) {
//handle overflow
}
//proceed with computing first * second
Run Code Online (Sandbox Code Playgroud)
看似不那么"干净"的方法是首先乘以然后用除法检查结果:
size_t result = first * second;
if( second != 0 && result / second != first )
//handle overflow
}
Run Code Online (Sandbox Code Playgroud)
然而,因为无符号数字乘以"安全溢出"通过绕零来实现,所以它可以正常工作并且看起来像以前的代码(首先检查,然后相乘).
第二个代码有任何潜在的问题吗?它会永远和第一个一样好吗?
C ++ 20将指定带符号整数类型必须使用二进制补码。鉴于(实际上?)每个实现当前都使用二进制补码,这似乎不是一个很大的变化。
但是我想知道这种改变是否会将某些“未定义的行为”转变为“实现定义”甚至“定义”。
考虑绝对值函数std::abs(int)及其一些重载。C ++标准通过引用C标准来包括此功能,该标准表示如果无法表示结果,则行为未定义。
用二进制补码时,没有与之相对应的正数INT_MIN:
abs(INT_MIN) == -INT_MIN == undefined behavior
Run Code Online (Sandbox Code Playgroud)
在符号幅度表示中,有:
-INT_MIN == INT_MAX
Run Code Online (Sandbox Code Playgroud)
因此,abs()留下一些未定义的行为似乎是合理的。
一旦需要二进制补码,abs(INT_MIN)就可以完全指定行为,或者至少定义实现,这似乎是有意义的,而没有任何向后兼容的问题。但我看不到有任何建议的改变。
我看到的唯一缺点是C ++标准将需要abs()明确指定,而不是引用C标准的abs()。(据我所知,C并不要求补码。)
这是否只是委员会的优先事项?还是有理由不利用两国补编任务规定所提供的简化和确定性?
进行编程时,我发现我的代码在使用条件时给出了运行时错误,i < vec.size() - 1但是对于来说可以正常工作i + 1< vec.size()。这里vec空无一人std::vector。
//giving error
vector<int> vec;
for (int i = 0; i < vec.size() - 1; i++)
{
//some code
}
//not giving error
vector<int> vec;
for (int i = 0; i + 1 < vec.size(); i++)
{
//some code
}
Run Code Online (Sandbox Code Playgroud) 在回答另一个问题时,提供了以下解决方案,由OpenBSD提供,为了简洁起见,
uint32_t foo( uint32_t limit ) {
uint32_t min = -limit % limit, r = 0;
for(;;) {
r = random_function();
if ( r >= min ) break;
}
return r % limit;
}
Run Code Online (Sandbox Code Playgroud)
这条线是如何uint32_t min = -limit % limit工作的?我想知道的是,是否有数学证据证明它确实为随机数计算了一些下限并充分消除了模偏差?
有没有办法防止这个问题中的代码产生二进制文件?理想情况下,在编译时通过错误.问题的示例代码:
unsigned int nVal = 0;
nVal = -5; // no error!
Run Code Online (Sandbox Code Playgroud)