为什么在更改 main 的签名时会出现段错误?
Why am I getting segfault when changing the signature of main?
我正在尝试接触 C,并编写了这个程序,它在随机位置显示 1 kb 的 RAM。这是代码,它工作正常:
#include <stdio.h>
int main(){
char *mem;
for(int i =0; i < 1024; i++){
mem++;
printf("%c", *mem);
}
return 0;
}
在那之后,我对我的代码进行了以下更改,每次 运行 我的程序都会出现段错误:
#include <stdio.h>
// Just added this signature
int main(int argc, char *argv[]){
char *mem;
for(int i =0; i < 1024; i++){
mem++;
printf("%c", *mem);
}
return 0;
}
我的蜘蛛感觉告诉我,我得到的段错误是随机的,也应该是在第一个例子中引起的,但是 运行一次又一次地使用不同的程序让它看起来像是可预测的行为。
$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
当您尝试
时,您的两个代码段都会调用 undefined behavior
- 越界(
mem++;
,没有分配)
- 使用未初始化的值(访问
*mem
)
使用当前版本。
记住,指针不会神奇地继承(或获取)内存,一般来说,您需要使指针指向有效的东西。
您从未初始化 mem
,因此其内容未定义。当您尝试使用 ++
增加它或取消引用指针时,您会得到 undefined behavior.
未定义行为可能发生的事情之一是程序可能看起来正常运行,而进行看似无关的更改会导致崩溃。
您需要初始化mem
。我猜你只是想读取随机内存,但这是不允许的。例如,您可能正在尝试读取由不同进程使用的内存,或者您可能正在尝试读取一些在您的计算机中甚至不存在的地址。
通过更改 main 的签名,您已经更改了 mem
中的随机垃圾值。它可能的工作方式是 mem
从某个寄存器中获取随机值。当您修改函数签名时,argc
和 argv
正在使用这些寄存器。因此 mem
正在获取垃圾堆栈值的不同垃圾寄存器值。在任何情况下,您都不应该尝试跟随垃圾指针。
仅仅因为它在一个示例中有效,只意味着你很幸运。你仍然不应该这样做。稍微改一下很可能就不行了。
mem
的值未定义(未初始化),但不是随机的。如果在调用 main 之前调用了其他 C 运行时函数,则 mem
使用的堆栈槽中可能有一个有效指针。将参数添加到 main 更改使用哪个插槽并更改行为。这可能意味着代码不会崩溃,尽管它不正确。
我正在尝试接触 C,并编写了这个程序,它在随机位置显示 1 kb 的 RAM。这是代码,它工作正常:
#include <stdio.h>
int main(){
char *mem;
for(int i =0; i < 1024; i++){
mem++;
printf("%c", *mem);
}
return 0;
}
在那之后,我对我的代码进行了以下更改,每次 运行 我的程序都会出现段错误:
#include <stdio.h>
// Just added this signature
int main(int argc, char *argv[]){
char *mem;
for(int i =0; i < 1024; i++){
mem++;
printf("%c", *mem);
}
return 0;
}
我的蜘蛛感觉告诉我,我得到的段错误是随机的,也应该是在第一个例子中引起的,但是 运行一次又一次地使用不同的程序让它看起来像是可预测的行为。
$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
当您尝试
时,您的两个代码段都会调用 undefined behavior- 越界(
mem++;
,没有分配) - 使用未初始化的值(访问
*mem
)
使用当前版本。
记住,指针不会神奇地继承(或获取)内存,一般来说,您需要使指针指向有效的东西。
您从未初始化 mem
,因此其内容未定义。当您尝试使用 ++
增加它或取消引用指针时,您会得到 undefined behavior.
未定义行为可能发生的事情之一是程序可能看起来正常运行,而进行看似无关的更改会导致崩溃。
您需要初始化mem
。我猜你只是想读取随机内存,但这是不允许的。例如,您可能正在尝试读取由不同进程使用的内存,或者您可能正在尝试读取一些在您的计算机中甚至不存在的地址。
通过更改 main 的签名,您已经更改了 mem
中的随机垃圾值。它可能的工作方式是 mem
从某个寄存器中获取随机值。当您修改函数签名时,argc
和 argv
正在使用这些寄存器。因此 mem
正在获取垃圾堆栈值的不同垃圾寄存器值。在任何情况下,您都不应该尝试跟随垃圾指针。
仅仅因为它在一个示例中有效,只意味着你很幸运。你仍然不应该这样做。稍微改一下很可能就不行了。
mem
的值未定义(未初始化),但不是随机的。如果在调用 main 之前调用了其他 C 运行时函数,则 mem
使用的堆栈槽中可能有一个有效指针。将参数添加到 main 更改使用哪个插槽并更改行为。这可能意味着代码不会崩溃,尽管它不正确。