为什么此代码实际工作?

问题描述:

我已经读了有点类似的问题(why this code works in C),但它实际上并没有得到解释,为什么是这一段代码实际工作:为什么此代码实际工作?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef struct example 
{ 
    char length[2]; 
} STRUCT; 

int main (void) 
{ 
    STRUCT test; 
    strcpy(test.length, "********"); 
    puts(test.length); 
    return 0; 
} 

我使用的代码块编译它,所以我猜测它是在我的字符串中分配更多空间来默认存储额外的星号......我真的不知道。也许我很幸运,但每次运行它都可以。

在上面的示例(链接)中,他将2个元素放在2的数组中,这里我使用的空间比字符串可以处理的要多得多,或者可以。

+1

HTTP://en.wikipedia。org/wiki/Buffer_overflow,是的,你很幸运。在你分配的界限之外写入的内容是未定义的行为,并且可能导致从绝对没有一直到崩溃操作系统的任何问题(或者可能更糟) –

+4

程序展示[*未定义的行为*](http:// en.wikipedia.org/wiki/Undefined_behavior)并且不合格。这只是运气,它运行,运气和[鼻恶魔](http://www.catb.org/jargon/html/N/nasal-demons.html)。 –

+1

欢迎来到未定义行为的世界。这是最糟糕的一种未定义的行为 - 代码起作用。它将工作多年,直到真正令人讨厌的事情发生。有时会以CNN或slashdot结尾 – pm100

你真幸运。

该结构只声明为两个字节长,但编译器或运行时间可能会分配更多或只是不关心内存位置struct - 事实是,strcpy将覆盖内存后struct,如果在更大的上下文中使用,它最终会覆盖某些对其他内容至关重要的内存,并且会根据所覆盖的内存类型以及使用的内存类型创建一个灾难性错误。

在你的情况下,程序只是退出,所以机会(幸运的是)没有人会使用你已经损坏的内存。

C不检查数组边界。它会导致缓冲区溢出和未定义的行为,如Ricky Mutschlechner在评论中所述。

+0

是的,我知道,我只是认为编译器可以帮助解决这种情况。 –

+0

@matt_s - 不,它不。 – Soren

它的工作原理是因为写入(但未分配)的内存未被此应用程序的其他部分使用。我不知道内存分配是如何工作的以及大块的细节。 只需搜索更多细节。

它不会使操作系统崩溃,但会在最坏的情况下导致分段错误。

+0

从技术上讲,因为它是UB,所以*可能会使操作系统崩溃。 –

+0

取决于操作系统。老,小,嵌入式 - 他们会崩溃 – pm100

+1

我同意,取决于操作系统。 http://stackoverflow.com/questions/15646973/how-dangerous-is-it-to-access-an-array-out-of-bounds – nvd

这是未定义行为的示例(正如人们在评论中提到的那样)。

至于为什么特别是这个工作,它很可能是由于堆栈对齐。因此,当您声明STRUCT test时,即使它只需要堆栈中的两个字节,编译器也会将堆栈向下对齐(通过为结构添加额外的填充),因此在test之后得到了额外的未使用空间,其中strcpy写入。因为程序中没有其他部分使用这个空间,所以它给人一种没有问题的幻觉。

它只是溢出你的堆栈,因为测试是堆栈。 现在可能没有任何问题,但是如果你在栈上声明了一些更多的变量以及测试,那可能会导致一些问题

+0

堆栈溢出是一种不同类型的错误。您可能想说“它正在**进入**堆栈”。 –

您正在写入位于test.length之后的堆栈内存中。为了说明这个问题好,我加了两行代码:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef struct example 
{ 
    char length[2]; 
} STRUCT; 

int main (void) 
{ 
    STRUCT test; 
    unsigned int foo = 42; 
    strcpy(test.length, "********"); 
    puts(test.length); 
    printf("%u", foo); 
    return 0; 
} 

您期望中的printf打印42,但是变量foo得到由strcpy的覆盖。真正的输出,例如在海湾合作委员会,在(你可以测试它here)以下:

******** 
707406378