2010-08-01 2 views
0

는 실행에 충돌 :는 작은 충돌 프로그램 다음 프로그램은 다음 g로 컴파일 ++하지만

다음 프로그램은하지 충돌 않습니다
class someClass 
{ 
public: 
    int const mem; 
    someClass(int arg):mem(arg){} 
}; 

int main() 
{ 
    int arg = 0; 
    someClass ob(arg); 

    float* sample; 
    *sample = (float)1; 

    return 0; 
} 

:

int main() 
{ 

    float* sample; 
    *sample = (float)1; 

    return 0; 
} 
+5

는 당신이 좋은 C++ 책을 가지고 있습니까 : 32 비트 릴리스 모드에서 MSVC++ 10에서

스크린 샷 (디버그 모드는 모든 변수 강제 이런 종류의 물건을 방지하기 위해 초기화)? 그렇게한다면 상당한 깊이의 포인터와 그 사용법을 논의해야합니다. 그렇지 않다면 [The Definitive C++ Book Guide and List] (http://stackoverflow.com/questions/388242/)에 나와있는 소개 도서 중 하나를 얻는 것이 좋습니다. –

+0

아니요, 아직 없습니다. 어려운 길을 배우는 것이 잘못된 이유는 무엇입니까? – user383352

+3

@ drenami : 당신은 근본적으로 당신을 가르치기 좋은 책이없는 프로그램을 작성하면서 C++의 걸림돌을 실제로 배울 수 없습니다. –

답변

8
float* sample; 
*sample = (float)1; 

sample은 가리 키도록 초기화되지 않습니다 개체를 참조 할 때 프로그램이 충돌합니다. 예를 들어 다음과 같이 사용하기 전에 초기화해야합니다.

float f; 
float* sample = &f; 
*sample = (float)1; 

두 번째 프로그램은 충돌하지 않아도 여전히 잘못되었습니다. 유효한 개체를 가리 키지 않는 포인터를 역 참조하면 정의되지 않은 동작이 발생합니다. 결과는 프로그램이 충돌하거나, 메모리의 일부 다른 데이터가 덮어 쓰여질 수 있으며, 응용 프로그램 이 올바르게 실행되거나 다른 결과가 나타나는 것으로 나타납니다. 귀하의 프로그램은 오늘 정상적으로 작동하지만 내일 실행할 때 충돌이 발생할 수 있습니다.

+2

... 이것은 100 % "어려운 방법"을 배우지 않는 좋은 이유입니다. 이런 일로 계속 야생 거위 추격을 할 것입니다. – tenfour

+0

무엇이 잘못되었는지 알아 내려고 할 때 그다지 중요하지 않습니다. :) 나는 컴파일러를 비난한다. – user383352

+5

컴파일러의 잘못이 아니므로 자신이하는 일에 단서가 없습니다. 순무의 손재주가 있고 손을 쳤기 때문에 망치를 비난하는 것과 같습니다. – Blindy

0

합니다. 두 번째 예는 당신을 위해 충돌하지 않는 이유

진짜 흥미로운 점은이 BTW 같은 문제를

을 가지고 있기 때문에,이다 : 나를 위해 (GCC 4.4, AMD64) 모두 예를 충돌.

왜 두 번째 예제가 사용자에게 충돌하지 않는지 정말로 관심이 있다면 디버깅 정보로 컴파일하고 디버거에서 시작하십시오.

+0

정의되지 않은 동작으로 이어 지므로 아무 것도 보증되지 않습니다. – GManNickG

4

약간의 생각을 한 후에 2 번째 예가 왜 충돌하지 않았는지 어느 정도 확실하게 말할 수 있습니다. 다음으로, 인수의 수 (int)와, char **와 인수와 char ** 로서도 환경 문자열 main를 호출하는 프로그램이 실행될 때

는 CRT (C 런타임) 스택 3 개 값을 푸시.

이제는 main 함수를 작성할 때 항상 처음 두 값을 읽고 함수의 인수 (있는 경우)를 전달합니다. 세 번째 인수를 포함하면 세 번째 값도 전달되고 그렇지 않으면 스택에 남아 있습니다. 그래서 프로그램의 시작 스택은 다음과 같습니다

첫 번째 예에서
+--------+ 
| # args | 
+--------+  
| args | 
+--------+ <------ stack pointer 
| envs | 
+--------+ 

첫 번째 예에서 전체 스택처럼 보이는, 그래서 당신이 다음 포인터, 스택에 int 및 구조체를 할당 :

+--------+ 
| # args | 
+--------+  
| args | 
+--------+ <------ stack pointer 
| arg | <------ your integer, initialized in code 
+--------+ 
| ob | <------ your struct, initialized in code 
+--------+ 
| sample | <------ your pointer, uninitalized = garbage 
+--------+ 

그래서 sample 순수한 쓰레기와이 프로그램을 충돌 역 참조하려고합니다.

+--------+ 
| # args | 
+--------+  
| args | 
+--------+ <------ stack pointer 
| sample | <------ pointer, uninitalized (!) 
+--------+ 

포인터가 여전히 uninitalized되어 있지만 덮어 값 배열 실제 포인터이다 envp이다 :

이제 두 번째 예에서, 스택은 다음과 같다 char **.역 참조 할 때, "char to pointers"의 배열을 되 찾을 수 있으므로 안전하게 덮어 쓸 수 있습니다 (원래 포인터로 더 이상 취급하지 않는 한). 메모리가 할당되고 사용할 수 있습니다.

이제는 구현이 많이 달라졌지만 컴파일러에 맞을 것으로 보입니까? gdb으로 덮어 쓰기 전에 (char**)sample이 실제로 환경 변수 배열을 가리키고 있는지 확인할 수 있습니다.

the pointer in action http://img651.imageshack.us/img651/5918/69916340.png

관련 문제