我想先进一步说,我还没有能够重新创建我只想用几行代码解释的问题(相信我,我试过)。而且,我已经解决了我在下面描述的问题。我只是想确定它为什么会发生。
我正在为C.写一个terminal code editor。在另一个架构中测试它(Arm,具体而言),我遇到了一个奇怪的错误 - 它不再向上滚动(只是向下)。我在main
:
} else if ((c + 64) == 'V'){
edit_scroll (&session, session.max_y / 2);
session.cursor = session.disp;
session.flags |= EDIT_FLAG_REPRINT;
} else if ((c + 64) == 'Y'){
//here
edit_scroll (&session, -1 * (session.max_y / 2)); /*
| |
Removing parenthesis causes compilation errors
in some platforms.
*/
session.cursor = session.disp;
session.flags |= EDIT_FLAG_REPRINT;
}
当负值传递给它时, edit_scroll
将向上滚动(如图所示)。我在添加这两个括号时修复了错误,并且我发现表达式在函数调用中正在评估2147483598
。请注意,当我运行此测试时(此变量代表终端高度),此编译中int
的最大值为2,147,483,647
,session.max_y
的大小为100
。
以下是edit_scroll
实施:
int edit_scroll (struct edit * session, int deltay){
// I printed deltay at this line, when I determined the value
int i = session->disp;
char * data = session->buffer.data;
if (deltay > 0){
for (; data[i] && deltay; i++){
if (data[i] == '\n'){
deltay--;
}
}
if (!deltay){
session->disp = i;
}
}
if ((deltay < 0) && (session->disp > 0)){
for (i--; i > 0; i--){
if (data[i - 1] == '\n'){
if (!(++deltay)){
break;
}
}
}
session->disp = i;
}
return 0;
}
就像我说的,我无法在小型测试程序中重现此错误。我和Clang和Gcc一起尝试过,他们都给出了同样的错误。为什么评估这样一个奇数?可以说这是编译错误吗?
-1 * session.max_y / 2
显示装配会有帮助吗?我应该发布更多源代码吗?我对发布整个代码犹豫不决,因为仅.c
个文件只比1800
行多一点。
答案 0 :(得分:3)
乘法和除法是左关联的。因此,如果删除括号,则表示您正在计算(-1 * session.max_y) / 2
而不是-1 * (session.max_y / 2)
。如果该max_y字段是无符号的,则该除法将在一种情况下进行符号扩展,而在另一种情况下它不会产生不同的结果。
答案 1 :(得分:1)
无论max_y
的值是多少,如果它是无符号的,那么当您将其乘以-1
时,-1
会在乘法发生之前转换为unsigned
,并且然后结果是unsigned
。
我建议在你做任何涉及负数的事情之前抛弃无符号。即使你没有进行除法,在将非常大的无符号结果(应该是负数)转换回有符号类型时,最终会出现整数溢出和未定义的行为。 (我怀疑这种溢出是你看到的编译错误的根源,因为否则一切都是明确的,只是以错误的方式。)