2013-05-07 6 views
3

왜이 segfault가 아닌가요?왜이 코드가 segfault를 발생시키지 않습니까?

#include <stdio.h> 
int main() 
{ 
    int i; 
    int arr[] = {1, 2, 3, 4}; 

    for(i=0;i<8;i++) 
    { 
     arr[i] = i; 
     printf(" %d", arr[i]); 
    } 

    printf("\n"); 

    return 0; 
} 

그러나 for 루프에서 8을 9로 바꾸면 작동합니다.

참고 : 나는 무엇이든지이 프로그램을 수행 할 수 있는지에 대해 전혀 보장이 없다는 것을 의미 undefined behavior 32 비트 크런치 뱅 리눅스에

+9

배열 끝을 지나서 읽는 것은 정의되지 않은 동작입니다. 정의되지 않은 동작은 아무 것도 될 수 없습니다. * 반드시 * segfault하지 않아도됩니다. – Cairnarvon

+2

순수한 행운. 쓰레기 번호를 출력하지 않니? – Humungus

+0

다른 지역화 된 라이더 ... : '( –

답변

14

기술적으로 말하면,이 프로그램이 결과를하려합니다. 그것은 원칙적으로 하드 드라이브를 포맷하거나, 불쾌한 메시지를 모든 친구들에게 보내거나, 컴퓨터를 켜거나, 감각적이고 노예가되는 인류가되게 할 수 있습니다.

이 경우 n = 8 일 때 정의되지 않은 동작은 아무 일도 일어나지 않지만 n = 9 일 때 정의되지 않은 동작은 segfault를 발생시킵니다. 둘 다 프로그램에 대해 완전히 허용되는 행동이지만 휴대용이 보장되지는 않습니다.

희망이 도움이됩니다.

0

templatetypedef의 대답은 (당신이 생각하는 것만 큼 흔한 일이다)이 정의되지 않은 동작의 경우와, 정확하지만 난 뭔가를 추가하고 싶습니다 :

9 *의를 sizeof (int)를의 전력 아니다 2. 컴파일러가 메모리를 할당 할 때 그들은 보통 heap의 단편화를 방지하기 위해 2 바이트의 출력으로 할당합니다.

대신 네가 물었던 것과 똑같이 4 * sizeof (int)를 할당하지 않은 이유가 궁금 할 수 있습니다. 확실하지는 않지만 컴파일러가 두 개의 추가 바이트를 할당하거나 배열에 할당 할 최소 메모리 양을 할당 할 수 있습니다. 컴파일러와 코드를 컴파일 한 옵션에 따라 다릅니다.

최적화없이 코드를 실행하려고하면 (명령 줄에서 -O0) 필요한 메모리 양과 i> = 4에 대해 segfault를 할당 할 수 있습니다.

C 컴파일러가 힙이나 스택에 정적 배열을 할당했는지 모르겠다.

+0

이 배열은 힙에 할당되어 있습니까?이 방법으로 선언 된 배열은 스택에 할당된다고 가정합니다. – templatetypedef

+0

@templatetypedef 고정 크기 배열을 비롯한 로컬 변수 'arr' 같은 코드는 대개 C/C++의 스택에 할당됩니다. –

2

@templatetypedef가 맞습니다. 그는 대답에 나를 때렸다. 정의되지 않은 동작이 반드시 segfault를 의미하는 것은 아닙니다.

그러나 나는 그것이 N = 9 세그먼테이션 폴트 (segfault)에 대한 이유와 같은 몇 가지 추측을 제공하고 싶지만 8. 일반적으로는, int iint arr[] 같은 변수가 아래로 성장하는의 stack에 있지. 따라서 i은 주소가 0x4000 일 수 있으며, 4 바이트 인 경우 int 인 경우 arr[0]0x4004, arr[1]0x4008 등입니다. 이 경우 컴파일러는 arr에 대해 16 바이트를 할당했을 가능성이 높으며 주소가 0x4014 (첫 번째 바이트는 arr, 즉 arr[5]의 첫 번째 바이트) 미만일 수 있습니다. 하지만 일반적으로 수동으로 선언하는 변수 외에도 스택에 다른 것들이 있습니다. 예를 들어 printf 호출에 대한 인수가 스택에 있고 다른 부기 정보가있을 수 있습니다. 따라서 arr[9]이 컴파일러에서 다른 용도로 사용하는 스택 위치와 일치하면 segfault로 이어질 수있는 실수로 해당 정보가 손상됩니다.

또는 arr[8]이 OS에서 할당 된 스택 프레임의 맨 아래에있는 경우 OS는 사용자의 프로세서가 arr[9]과 일치하는 주소에서 값을로드하거나 저장하라는 명령을 실제로 거부하도록 프로세서를 구성했을 것입니다. 스택 크기는 일반적으로 4KB 정도이므로이 시나리오는 불가능하다고 생각합니다. 그런 짧은 프로그램의 경우 할당 된 스택의 끝 부분에 아무 것도 없어야합니다.

+0

@templatetypedef는 정의되지 않은 동작을 올바르게 말합니다.이 같은 분석을 보았습니다. 루프에서 실행되는 동안 arr은 스택 맨 위에 있어야합니다 printf가 호출 될 때 컴파일러에 따라 arr [5] 또는 arr [9] 이상의 주소가 더 높은 주소로 이동합니다. arr [5] 이후로 printf의 실행에 영향을 미치지 않아야한다. printf arr의 back이 다시 stack의 맨 위에있을 때. – Siddique

관련 문제