2012-01-02 5 views
1
#include<stdio.h> 

int main() 
{ 
     const int sum=100; 
     int *p=(int *)&sum; 

     *p=101; 


     printf("%d, %d",*p,sum); 
     return 0; 
} 

/*동작 후, 일정한 정수 변수

출력

101, 101

*/

P 점에서 INT 왜/어떻게하면 * 합계의 가치를 바꿀 수 있습니까?

+0

다른 최적화 설정으로 시도해보십시오. 대부분의 컴파일러는 101, 100을 충분히 최적화 할 수 있도록 인쇄합니다. –

답변

6

정의되지 않은 동작입니다. 코드의 버그입니다. 코드가 '효과가있는 것'이라는 사실은 의미가 없습니다. 컴파일러는 프로그램을 충돌 시키거나 프로그램이 무의미한 (예 : const가 아닌) 값을 변경하도록 허용합니다. 아니면 뭔가 다른 것을하십시오. 행동에 대한 요구 사항이 없기 때문에 행동에 대해 '이유'를 부여하는 것은 의미가 없습니다.

코드가 C++로 컴파일되면 C++이 암시 적으로 const을 버리지 않으므로 오류가 발생합니다. 잘하면, C로 컴파일 될 때조차도 경고를 받게 될 것입니다.

+0

+1 UB의 마법의 땅에 들어갔다. –

+0

코드를 .cpp로 컴파일하고 출력으로 다음을 얻었습니다. 101, 100 괜찮 았지만 출력이 더 정상적으로 여기 컴파일됩니다. – sbose

+2

참고 : C++에서 컴파일하지 않는다고 (int *) 캐스트가 코드에 없었습니다. 이 캐스트는 코드를 C++로 컴파일하지만'* p = 101; '표현식은 여전히 ​​정의되지 않은 동작입니다. 당신에게 이해되는 것을 가지고 있다는 사실은 여전히 ​​중요하지 않습니다. –

2

p에는 변수 sum의 메모리 주소가 포함됩니다. *p 구문은 sum의 실제 값을 의미합니다.

당신이 말하고있는

*p=101 

말할 때 : (변수 sum가 저장되어있는 주소) 주소 p로 이동하여 값을 변경합니다. 따라서 실제로 변경하는 사람은 sum입니다.

+1

그건 내 요점이야. sum이 const로 정의 된 경우 어떻게 변경해야합니까? – sbose

+3

const는 메모리 위치를 보호하지 않습니다. 변수 합계 만 보호합니다. Const는 컴파일시에만 점검됩니다. –

2

컴파일러에게 "이 변수를 수정해서는 안되며 말해봐"라고 말하는 컴파일 타임 플래그로 const을 볼 수 있습니다. 변수를 실제로 수정할 수 있는지 여부에 대해서는 아무 것도 시행하지 않습니다.

그리고 있습니다는 const가 아닌 포인터를 통해 그 변수를 수정하기 때문에, 컴파일러는 실제로 당신을 말할 것입니다 : 당신은 당신의 자신의 약속을 깨고

main.c: In function 'main': 
main.c:6:16: warning: initialization discards qualifiers from pointer target type 

를, 컴파일러는 경고를 표시하지만, 당신에게 드릴 것입니다 행복하게 진행하십시오.

+0

안녕하세요, int * p = (int *) ∑에 질문을 편집했습니다. 경고가 표시되지 않습니다. – sbose

+0

@SHOUBHIKBOSE 강제로'(int *)'로 캐스팅하기 때문에 컴파일러에게 "닥쳐, 내가하는 일을 안다". 그래서 아무 경고도. –

1

동작이 정의되지 않았습니다. 즉, 다른 컴파일러 구현, 아키텍처, 컴파일러/최적화 프로그램/링커 옵션에서 다른 결과가 발생할 수 있습니다. 분석을 위해서


, 여기있다 :

(면책 조항 :. 내가 컴파일러를 모르는 이는 컴파일러가이 상황을 처리하기 위해 선택할 수있는 방법에 단지 논리적 인 추측에서이다 순진 어셈블리 언어 디버거 관점.)

  • 일정한 정수를 선언, 컴파일러는 주소 또는 비 주소 만들기의 선택의 여지가있다.수명 정적 것이다
    • :
      • 번지는 정수 값이되도록 실제 메모리 위치를 차지하는 것을 의미한다.
      • 이 값은 이진 코드에 하드 코딩되거나 프로그램 시작 중에 초기화 될 수 있습니다.
      • 포인터로 액세스 할 수 있습니다.
      • 주소를 아는 모든 이진 코드에서 액세스 할 수 있습니다.
      • 읽기 전용 또는 쓰기 가능한 메모리 섹션에 배치 할 수 있습니다.
      • 일상적인 CPU의 경우 쓰기 권한이 메모리 관리 장치 (MMU)에 의해 적용됩니다. MMU를 망치는 것은 지저분한 사용자 공간에서 불가능하며 단순한 const 정수 값으로는 가치가 없습니다.
      • 따라서 간단하게하기 위해 쓰기 가능한 메모리 섹션에 배치됩니다.
      • 컴파일러가 쓰기 금지 메모리에 배치하도록 선택하면 쓰기 금지 메모리에 쓰기를 시도 할 때 프로그램이 충돌합니다 (액세스 위반).
      • 마이크로 컨트롤러를 별도로 설정하십시오. 마이크로 컨트롤러를 사용하고 있다면이 질문을하지 않았을 것입니다.
    • 주소 지정이 가능하지 않은 것은 메모리 주소를 차지하지 않는다는 것을 의미합니다. 대신 변수를 참조하는 모든 코드 (예 : 해당 정수의 값 사용)는 sum의 모든 인스턴스를 리터럴 100으로 변경하기 위해 찾기 및 바꾸기를 수행하는 것처럼 r 값을받습니다.
      • 어떤 경우에는 컴파일러 으로 지정할 수 없습니다. 컴파일러가 주소를 알고있는 경우 컴파일러는 해당 값을 메모리에 저장해야한다는 것을 알고 있습니다. 귀하의 코드는이 사건에 속합니다. 변수가 을 제거되었을 수 있고 printf이의 분위기에 따라 달라집니다 int main() { printf("%s, %s", (b1? "100" : "101"), (b2? "100" : "101")); return 0; }b1b2로 전환됩니다
      • 그러나, 일부 적극적으로-최적화 컴파일러, 그것 이외의 주소를 만들기 위해 전적으로 가능하다 컴파일러.
        • 는 메모리 위치를 할당하지만, 일정한 문자와 모든 참조를 대체 : 그것은 그 중 하나, 또는 완전히 다른, 심지어 뭔가를 할 수 -
      • 컴파일러는 종종 분할 결정을 내릴 것입니다. 이 경우 디버거에서 값이 0이지만 해당 위치를 사용하는 모든 코드에 하드 코딩 된 값이 포함 된 것으로 표시됩니다.
    • 일부 컴파일러는 캐스트가 정의되지 않은 동작을 일으키고 컴파일을 거부 할 수 있음을 감지 할 수 있습니다.