为什么这个C代码片段不会导致分段错误?
这是视频教程中的代码片段。我不确定我是否理解为什么代码在运行时不会导致分段错误为什么这个C代码片段不会导致分段错误?,c,pointers,casting,dereference,C,Pointers,Casting,Dereference,这是视频教程中的代码片段。我不确定我是否理解为什么代码在运行时不会导致分段错误 (unsigned int*)(argv[1])这看起来像是传递给程序的第一个参数被强制转换为无符号int。因此,如果参数是“AAAA”,那么“0x4141”现在是指向内存中某个位置的指针 然后当我们这样做时-*((unsigned int*)(argv[1]),我们不是在推迟address0x4141所指向的值吗?据我所知,进程可能无法访问此地址。那么,为什么没有出现分段错误呢?程序的输出是- ptr1=0x414
(unsigned int*)(argv[1])
这看起来像是传递给程序的第一个参数被强制转换为无符号int。因此,如果参数是“AAAA”,那么“0x4141”现在是指向内存中某个位置的指针
然后当我们这样做时-*((unsigned int*)(argv[1])
,我们不是在推迟address0x4141
所指向的值吗?据我所知,进程可能无法访问此地址。那么,为什么没有出现分段错误呢?程序的输出是-
ptr1=0x4141
我用gcc在Linux上编译了这个程序 注意:此答案解释了代码在这种特殊情况下的工作原理,有关更完整的答案,请参阅@Lundin post
(unsigned int*)(argv[1])
将char*
转换为unsigned int*
*((unsigned int*)(argv[1])
将取消引用转换为char*
假设,argv[1]
指向AAAA
字符串。它以41
(十六进制)的形式存储在内存中。然后将其解释为无符号int
,结果是ptr1=0x4141
请看下图:左侧查看器将内存解释为char*
,右侧查看器将内存解释为unsigned int*
(不关心小端/大端的差异):
因此,没有理由使用segfault此代码既危险又糟糕。一步一步地解释代码的作用以及原因:
是指向字符的指针数组(argv
)。或者,如果您愿意,可以使用指向字符指针数组中第一项的指针(char*[]
)char**
指向可执行文件的名称,argv[0]
是指向传递的第一个参数的指针argv[1]
将指向第一个参数的指针((unsigned int*)(argv[1])
)强制转换为指向int的指针(char*
)。这决不能保证是安全的转换。这里有两个主要错误:unsigned int*
- 如果这个新的整数地址未对齐,访问它将调用未定义的行为,可能导致程序崩溃
- 该转换违反了严格的别名规则,该规则(简单地说)指出编译器可能会假设
指向的内容从未通过其他随机指针类型访问过。因此,编译器可能会假定程序从未使用argv[i]指向的内存。在调用未定义的行为时,可能会发生任何奇怪的优化char*
- 如果特定编译器将指针转换的确定性行为指定为非标准扩展,那么它将尝试访问指向的字符串,就像它是一个整数一样。例如,如果字符串是
,则结果整数(假定为32位)将是“ABCD”
或0x41424344
。这取决于CPU的持久性。这样的代码是不可移植的0x44434241
argv
数组指向的内存当然不会产生任何影响。如果无法读取此内存,则无法使用argv参数。它们的具体存储方式取决于操作系统,但它必须位于允许进程访问的地址空间内
因此,只要您在分配的内存中保持访问权限,程序肯定不会因此而崩溃或seg故障。如果字符串
argv[1]
只有1个字符长,您可能会遇到seg错误。argv[1]
持有指向char
数据的指针,您可以将该指针(而不是它所指向的)转换为指向无符号int
数据的指针,然后取消引用该指针。您没有取消引用0x4141
。您正在取消引用argv[0]
,但使用的是unsigned int*
彩色眼镜。很抱歉,这不是一个好的答案,因为您几乎没有提到代码中所有定义不好的行为。阅读此答案的读者可能会认为OP的代码是完美的代码,并且提到的教程不是垃圾。因此,没有理由使用segfault
它是不正确的,有。您可以将任何内容强制转换为char*
,但如果以相反的方式执行,则会调用未定义的行为。它不能保证工作,因为argv[1]
不一定正确对齐。它在这里工作只是因为x86支持未对齐的访问,但大多数其他体系结构都是禁止的it@Lundin,同意。正在等待OP取消选中“接受”按钮,以便删除答案。建议:请立即停止观看Youtube教程。留下评论,说这是一个糟糕的教程。请随意发布此帖子的链接,以警告其他人不要观看。事实上,作者承认代码很糟糕,但上下文不同。这是视频的一个链接。@user1720897好吧。。。杜尔。该视频中的代码与您的问题中的代码不同。他将结果存储在无符号整数*
中,而您将其存储在无符号整数
中。完全不同的程序(但同样糟糕)。这段视频似乎是关于将数据侵入不同的静态内存位置,并以车库黑客通常的心态:“让我们希望这能奏效”或“哇,这一次奏效了”。是的。代码是不同的。我在玩代码,试图向自己解释代码,但我偶然发现了一些我不理解的东西。@user1720897存储结果
int main(int argc, char **argv) {
unsigned int ptr1 = *((unsigned int *)(argv[1]));
printf("ptr1 = 0x%x\n", ptr1);
exit(0);
}