【发布时间】:2017-07-19 12:58:01
【问题描述】:
以下示例在调用look_back_1() 或look_back_2() 时会崩溃。 原因:当对无符号变量取反时,结果应保持无符号。
#include <stdio.h>
int look_back_1(int *arr, unsigned int nmElems, unsigned long dist)
{
int *elem = arr + nmElems;
elem += -dist;
return (*elem);
}
int look_back_2(int *arr, unsigned int nmElems, unsigned int dist)
{
int *elem = arr + nmElems;
elem += -dist;
return (*elem);
}
int main(int argc, char **argv)
{
int arr[100] = { 0, };
printf("1. %d\n", look_back_1(arr, 100, 1)); // <NEEDS TO CRASH, BUT WORKS????>>
printf("2. %d\n", look_back_2(arr, 100, 1)); // <<CRASH!!!!!>>
}
在执行数组越界访问时,GCC 4.5 会在每个函数调用中崩溃。 对于这两种情况,编译器都会发出 NEG 操作码。
GCC 6.1 或 Clang 只会在调用 int 版本时崩溃。 但是当它们为 unsigned long 版本发出 SUB 操作码时,它们都避免了崩溃。
他们可以这样做吗?
【问题讨论】:
-
没有“正确崩溃”之类的东西。 - 你所拥有的是未定义的行为。
-
编译器应该永远不会崩溃,而且它不太可能崩溃。 “崩溃”是什么意思?添加不应该失败。但是,您正在使用该函数来访问数组的边界。这可能导致程序在运行时崩溃。打印地址以了解灾难发生的原因。
-
为了充分理解,了解您的代码是否编译为 64 位可能很重要。您使用的是 64 位操作系统吗?编译命令行是否有“-m32”?
unsigned long和unsigned int的大小是多少?你可以edit你的问题来提及这些细节。 -
我想知道您是否了解一元
operator-对unsigned值的作用。它定义明确,不会产生负值。 -
你是在问是否允许编译器创建一个不会崩溃的程序?如果是这样,答案总是肯定的。未定义的行为可以做任何事情,包括不崩溃。