const로 정의된 객체의 값을 포인터를 통해 변경할 수 있습니까?
#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
될까요?
이것은 "정의되지 않은 행동"입니다. 이것을 시도할 때 어떤 일이 일어날지를 기준으로 예측할 수 없다는 것을 의미합니다.특정 기계, 컴파일러, 프로그램의 상태에 따라 다른 작업을 수행할 수 있습니다.
이 경우 가장 자주 발생하는 것은 "예"입니다. 변수는 상수든 아니든 간에 단지 메모리의 한 위치일 뿐이며, 일정성의 규칙을 어기고 간단히 덮어쓸 수 있습니다. (물론 프로그램의 다른 부분이 일정한 데이터에 의존하고 있다면 심각한 버그를 일으킬 것입니다!)
그러나 경우에 따라서는 -- 대부분의 경우 다음을 위해const static
data -- 컴파일러는 이러한 변수를 읽기 전용 영역의 메모리에 넣을 수 있습니다.예를 들어 MSVC는 일반적으로 실행 파일의 .text 세그먼트에 고정 int를 넣는데, 이는 사용자가 파일에 쓰려고 하면 운영 체제가 보호 오류를 던져 프로그램이 중단된다는 것을 의미합니다.
컴파일러와 머신의 다른 조합에서는 완전히 다른 일이 일어날 수 있습니다.당신이 확실히 예측할 수 있는 한 가지는 이 패턴이 당신의 코드를 읽어야만 하는 사람들을 짜증나게 할 것이라는 것입니다.
명확하지 않은 행동입니다.증명:
/* program.c */
int main()
{
const int a = 12;
int* p;
p = &a;
*p = 70;
printf("%d\n", a);
return 0;
}
gcc program.c
실행합니다.출력은 70(gcc 4.3)이 됩니다.
다음과 같이 컴파일합니다.
gcc -O2 program.c
실행합니다.출력은 12가 될 것입니다.최적화를 수행할 때 컴파일러는 아마도 레지스터에 12를 로드하고 a가 변경될 수 없다는 것을 "알기" 때문에 인쇄용 a에 액세스해야 할 때 다시 로드하지 않습니다.
수정 aconst
포인터를 통해 정규화된 개체는 정의되지 않은 동작을 호출하며, 그 결과입니다.이는 특정 구현에서 기대할 수 있는 것일 수 있습니다(예: 이전 값은 변경되지 않음)..text
.
그것은 정말로 gcc와 함께 작동합니다.그래도 마음에 안들었어요.
test.c:6: warning: assignment는 한정자를 포인터 대상 유형에서 폐기합니다.
그러나 실행 시 값이 변경되었습니다.명백한 '아니오'는 지적하지 않겠습니다...
네, 그런 코드를 사용해서 할 수 있습니다.그러나 코드는 언제 적용되지 않습니다.a
is global (gcc-compiled 프로그램이 나에게 준segmentation fault
.)
일반적으로 말하면, 사랑하는 C에서는 거의 항상 변경되거나 노출되어서는 안 되는 것들을 해킹할 수 있는 방법을 찾을 수 있습니다.여기서 한 예가 됩니다.
하지만 가난한 사람(아마도 6개월 후의 제 자신)을 생각하면, 저는 종종 그렇게 하지 않기로 결정합니다.
여기서 포인터 유형p
이다.int*
, 유형의 가치를 부여받고 있는 것.const int*
(&a
=> 의 주소=> aconst int
변수).
암묵적 캐스트는 일관성을 제거하지만, gcc는 경고를 던집니다(이는 구현에 따라 크게 달라집니다).
포인터가 a로 선언되지 않았으므로const
, 이러한 포인터를 사용하여 값을 변경할 수 있습니다.
만약 그 포인터가 다음과 같이 선언된다면.const int* p = &a
, 당신은 할 수 없을 것입니다.*p = 70
.
이 코드에는 제약 조건 위반이 포함되어 있습니다.
const int a = 12;
int *p;
p = &a;
위반된 제약 조건은 C116.5.16.1/1 "Simple assignment"입니다. 두 피연산자가 모두 포인터라면 왼쪽이 가리키는 유형에는 오른쪽이 가리키는 유형의 모든 한정자가 있어야 합니다. (그리고 유형 sans 한정자는 호환되어야 합니다.)
그래서 제약을 위반한 것은&a
활자가 있습니다const int *
있습니다.const
한정자로서; 그러나 해당 한정자는 다음 유형에 나타나지 않습니다.p
어느 것이int *
.
컴파일러는 진단을 내보내야 하며 실행 파일을 생성할 수 없습니다.프로그램이 언어의 규칙을 준수하지 않기 때문에 실행 파일의 동작은 완전히 정의되지 않습니다.
상수 변수를 가리키는 포인터를 사용하여 상수 변수의 값을 변경할 수 없습니다.이 유형의 포인터를 다음과 같이 부릅니다.Pointer to a constant
.
또 다른 개념이 있습니다.Constant Pointer
, 가 메모리 다른 할 수 즉, 포인터가 메모리 위치를 가리키면 다른 위치를 가리킬 수 없습니다.
나쁜 생각, 나쁜 생각.
또한 플랫폼 및 구현별 동작을 수행합니다.상수가 쓰기 불가능한 메모리에 저장되어 있는 플랫폼에서 실행 중인 경우, 이는 분명히 작동하지 않습니다.
도대체 왜 그러고 싶으십니까?출처의 상수를 업데이트하거나 변수로 만듭니다.
의 값을 변경할 때의 문제const
변수는 컴파일러가 그런 일이 일어날 것으로 예상하지 않는다는 것입니다.다음 코드를 고려합니다.
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", a);
컴파일러는 왜 다음과 같이 읽을까요?a
마지막 진술에서?컴파일러는 알고 있습니다.a
가12
그러니깐const
, 절대 변하지 않을 겁니다따라서 옵티마이저는 위의 코드를 다음과 같이 변환할 수 있습니다.
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", 12);
이것은 이상한 문제로 이어질 수 있습니다.예를 들어 최적화되지 않은 디버그 빌드에서는 코드가 원하는 대로 작동할 수 있지만 최적화된 릴리스 빌드에서는 실패합니다.
실제로 좋은 옵티마이저는 전체 코드를 다음과 같이 변환할 수 있습니다.
printf("%d\n", 12);
이전의 다른 모든 코드가 컴파일러의 눈에는 아무런 영향을 미치지 않습니다.효과가 없는 코드를 제외하면 전체 프로그램에도 영향이 없습니다.
반면에, 괜찮은 컴파일러는 당신의 코드가 결함이 있다는 것을 인식하고 당신에게 경고할 것입니다.
int * p = &a;
사실은 틀렸습니다.정답은 다음과 같습니다.
const int * p = &a;
~하듯이p
에 대한 포인터가 아닙니다.int
, 그것은 에 대한 지시입니다.const int
그렇게 선언되면 다음 줄은 하드 컴파일 오류를 발생시킵니다.
경고를 없애려면 다음을 캐스팅해야 합니다.
int * p = (int *)&a;
그리고 훨씬 더 훌륭한 컴파일러는 이 캐스팅이 그것을 깨뜨린다는 것을 인식할 것입니다.const
약속하고 옵티마이저에게 치료하지 말 것을 지시합니다.a
~하듯이const
.
보시다시피 컴파일러의 품질, 기능 및 설정은 결국 어떤 동작을 기대할 수 있는지를 결정하게 됩니다.이는 동일한 코드가 다른 플랫폼에서 또는 동일한 플랫폼에서 다른 컴파일러를 사용할 때 다른 동작을 나타낼 수 있음을 의미합니다.
C 표준이 그 경우에 대한 동작을 정의했다면 모든 컴파일러가 구현해야 할 것이고 표준이 무엇을 정의했든 구현이 어려워 컴파일러를 작성하려는 모든 사람에게 큰 부담이 되었을 것입니다.비록 표준이 "이것은 금지되어 있다"고 방금 말했다 하더라도, 모든 컴파일러는 이 규칙을 적용하기 위해 복잡한 데이터 흐름 분석을 수행해야 할 것입니다.그래서 표준은 그것을 정의하지 않습니다.다음과 같이 규정하고 있습니다.const
값은 변경할 수 없고, 어쨌든 값을 변경할 방법을 찾는다면 의지할 수 있는 행동이 없습니다.
예, 상수 변수의 값을 변경할 수 있습니다.
다음 코드를 사용해 보십시오.
#include <stdio.h>
int main()
{
const int x=10;
int *p;
p=(int*)&x;
*p=12;
printf("%d",x);
}
언급URL : https://stackoverflow.com/questions/3801557/can-we-change-the-value-of-an-object-defined-with-const-through-pointers
'programing' 카테고리의 다른 글
POI를 사용하여 숫자 형식으로 Excel 셀 값 설정 (0) | 2023.11.05 |
---|---|
Oracle PL/SQL where 절에서 변수를 사용하는 방법 (0) | 2023.11.05 |
$파일의 각 $파일에 대한 PowerShell (0) | 2023.10.31 |
각도 사용법.각 컨트롤러 또는 스코프에서 Json에게 (0) | 2023.10.31 |
AngularJS는 ng-model에서 포맷된 날짜를 얻습니다. (0) | 2023.10.31 |