2010-07-13 131 views
4

我偶然发现了一些“有趣”的东西,我不能把我的手指为什么行为不一致。为什么没有这段错误

检查此代码。

char buf[100]; 
sprint(buf,"%s",bla); 

简单,正确。当指针blaNULL指针时,很容易理解发生了什么。

这应该总是segfault正确!?

在一台机器上执行segfaults,在另一台机器上(我的开发机器),它只是照常营业。

我的开发PC正在运行Windows7,我正在编译gcc/MingW。计算机崩溃的位置是XP,并且安装了Visual studio 6

为什么地球上不会在我的PC上崩溃!?

干杯

+1

只是提到它:我知道这是测试代码,但在大多数情况下,您可能应该使用'snprintf()'而不是'sprintf()'。 – ereOn 2010-07-13 09:23:03

+2

除非你需要测试你的代码是否与严重不合规的编译器兼容,否则我会考虑用本世纪的东西替换Visual Studio 6。 – 2010-07-13 09:56:54

+1

所有答案都是不确定的行为 - 但是,只是一个想法:你*正面* bla是空吗?它可能是未初始化的?这是系统之间差异的更常见原因。 – 2010-07-13 10:16:50

回答

24

ISO C99: 7.19.6.3 The printf function

梗概

#include <stdio.h> 
int printf(const char * restrict format, ...); 

The printf function is equivalent to fprintf with the argument stdout interposed before the arguments to printf.

7.19.6.1 The fprintf function

7.19.6.1.9

If a conversion specification is invalid, the behavior is **undefined**. If any argument is not the correct type for the corresponding conversion specification, the behavior is **undefined**.

所以,你的代码调用未定义行为 [(ISO C99 3.4.3) behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes **no requirements**]

应该始终段错误的权利!?

不一定,未定义行为意味着任何东西都可能发生。

+6

很好地研究过,Prasoon,'+ 1'! – sbi 2010-07-13 13:48:15

+0

谢谢@sbi:).... – 2010-07-13 13:58:50

+17

有一天,我将制作一个编译器,每次调用未定义的行为时,都会开始播放*飞行的Valkyrie *。 – rlbond 2010-07-13 16:32:24

3

由于打印空引用作为字符串(据我所知,还没有与标准验证)不确定。许多系统将在结果中输出(null)

这是与其他的printf函数相同:

printf ("%s", NULL); // Outputs (null) to the console on some systems but can crash others 
1

除此之外,段错误是从来没有保证。如果它发生,某处出现错误;但在某处出现错误并不意味着段错误。

1

这应该总是segfault正确!?

不需要。它取决于编译器标准库附带的sprintf函数的实现。

据我所知sprintf规范并没有说你应该提供一个非空地址。

11

这应该总是segfault正确!?

不会。这会调用未定义的行为。分段错误只是调用UB的许多可能结果之一。

+0

+1:但是这引发了以下问题:有没有办法确保某些东西会导致“SEGFAULT”? ('kill my_program SEGFAULT'不是答案) – ereOn 2010-07-13 09:28:54

+0

'raise(SIGSEGV);'或者,虽然没有标准说明这必须工作,但是*(char *)0 = 0;也相当可靠。 – 2010-07-13 09:36:59

+4

+1由于某种原因,未定义的行为被称为“未定义”。 – 2010-07-13 09:43:57

0

这一切都取决于当时bla指的是什么。 sprintf()会做的是复制bla指向的所有字符,直到它遇到一个零(0x00)字符。

如果在达到buf [100]的极限之前遇到零字符,那么没有段错误,因为我们没有写入超出buf限制。另外,在某些系统中,如果bla指向读访问受保护的内存区域,则只要数据被读取,它也可能导致段错误。