pav*_*ala 19 c undefined-behavior
访问指针非法指针的程序不会因SIGSEGV而崩溃.这不是一件好事,但我想知道这是怎么回事以及这个过程如何在生产中存活了很多天.这对我来说很困惑.
我已经将这个程序用于Windows,Linux,OpenVMS和Mac OS,他们从未抱怨过.
#include <stdio.h>
#include <string.h>
void printx(void *rec) { // I know this should have been a **
char str[1000];
memcpy(str, rec, 1000);
printf("%*.s\n", 1000, str);
printf("Whoa..!! I have not crashed yet :-P");
}
int main(int argc, char **argv) {
void *x = 0; // you could also say void *x = (void *)10;
printx(&x);
}
Run Code Online (Sandbox Code Playgroud)
wal*_*lyk 29
缺少内存故障我并不感到惊讶.该程序没有取消引用未初始化的指针.相反,它是从指针变量开始复制和打印内存的内容,以及超出它的996(或992)个字节.
由于指针是一个堆栈变量,因此它会在堆栈顶部附近打印内存.该内存包含以下堆栈帧main():可能是一些保存的寄存器值,一个程序参数计数,一个指向程序参数的指针,一个指向环境变量列表的指针,以及一个main()要返回的保存指令寄存器,通常在C运行时库启动代码.在我调查的所有实现中,下面的堆栈帧包含环境变量本身的副本,指向它们的指针数组,以及指向程序参数的指针数组.在Unix环境中(您提示您正在使用),程序参数字符串将低于该环境.
所有这些内存都是"安全"的打印,除了一些不可打印的字符会出现,这可能会弄乱显示终端.
主要的潜在问题是是否有足够的堆栈内存分配和映射以防止访问期间的SIGSEGV.一个段故障,如果有太少的环境数据可能发生.或者,如果实现将该数据放在别处,那么这里只有几个堆栈的话.我建议通过清除环境变量并重新运行程序来确认.
如果任何C运行时约定不正确,则此代码不会如此无害:
void *x在堆栈上分配局部变量()main()使用参数调用.(某些轻载环境,如嵌入式处理器,main()无需参数即可调用.)在所有主流的现代实现中,所有这些通常都是正确的.
Dev*_*lar 17
非法内存访问是未定义的行为.这意味着您的程序可能会崩溃,但不能保证,因为确切的行为是未定义的.
(开发人员之间的一个笑话,特别是当面对那些不注意这些事情的同事时,"调用未定义的行为可能会格式化你的硬盘,它只是不能保证".;-))
更新:这里有一些热门的讨论.是的,系统开发人员应该知道给定系统上实际发生了什么.但是这些知识与CPU,操作系统,编译器等有关,并且通常具有有限的用途,因为即使你使代码工作,它仍然质量很差.这就是为什么我将答案限制在最重要的一点,并且问到了实际问题("为什么不会崩溃"):
问题中发布的代码没有明确定义的行为,但这只是意味着你不能真正依赖它的作用,而不是它应该崩溃.