상수(const)의 정의가 궁금합니다...

mastr99의 이미지

EC++ 다시 읽어보는 중에 const_cast에 대해 궁금증이 생겼습니다.

그냥 변수/객체의 상수성을 없애준다고만 알고 있었고 실제 코딩에서 사용한 적이 없어서 어물쩡 넘어갔었는데요..

int main(void)
{
	int a = 0 ;
	const int &ra = a ;
	int &rra = const_cast<int&>(ra) ;
	rra = 10 ;
	printf( "%d\n", a ) ;	/// a=10
 
	const int b = 0 ;
	int &rb = const_cast<int&>(b) ;
	rb = 10 ;
	printf( "%d\n", b ) ;	/// b=0 
 
	const int *pC = new int(0) ;
	int *ppC = const_cast<int*>(pC) ;
	*ppC = 10 ;
	printf( "%d\n", *pC ) ; /// *pC=10 ???
 
	return 0;
}

생각해보니 애초에 상수로 선언된 변수 b는 값을 바꾸는 동작 자체가 잘못되었으니
두번째 예제는 코드 자체가 잘못된 것 같고,

세번째 예제는 pC가 가르키는 값이 heap영역에 선언되었으니 값이 바뀌는 것인지...애매하구요....

그냥 const_cast의 정의를 "상수포인터", "상수레퍼런스"의 상수성을 제거한다 라고 이해하는게 맞는 것일까요?

부족한 글 읽어주셔서 감사합니다.

익명 사용자의 이미지

C++(C가 아니라)에서 '어떤 장소에 있는 값을 바꾸지 않겠다'라는 것과 '어떤 값에 이름을 붙이겠다' 라는 의도를 구분해야 합니다.

const int b = 0; 라고 쓰면 0이라는 값에 'b'라는 이름을 붙이겠다 라고 말하는 것입니다.
* 여기에 '장소'이라는 개념은 들어가지 않습니다. *
컴파일러는 이후에 등장하는 이름 'b'를 0으로 바꿉니다.
printf( "%d\n", b ); 가 0을 출력하는 이유가 그 때문입니다.

심지어 이렇게 써도 말이죠.

int &rb = const_cast(b);
rb = 10 ;

애초에 b를 위한 '장소'는 없는데 사용자가 억지로 non-const 참조를 하라고 하니 컴파일러는 이름이 없는 장소를 하나 만들고 여기에 'b'의 값 0을 집어 넣습니다.
rb는 이를 참조하죠.

결국 위 코드는 다음과 같이 쓴 것과 동일한 효과가 있습니다.

int rb = b;
rb = 10;

절대 rb가 참조하는 대상이 b인 것이 아닙니다.

int a = 0 ;
const int &ra = a ;
int &rra = const_cast(ra) ;

컴파일러는 위 코드를 보고 다음과 같이 해석합니다.

1. 새로운 장소에 0을 넣고 여기에 이름 'a'를 붙인다.
2. 그 장소에 ra라는 이름을 또 붙이되 'ra'라는 이름을 사용한 수식에서는 그 장소의 값을 바꾸는 행위를 금지한다.
3. 마찬가지로 그 장소에 rra라는 이름을 붙이되 'rra' 라는 이름을 사용한 수식에서는 그 장소의 값을 바꾸는 행위를 허락한다.

a, ra, rra는 모두 한 장소를 가리킵니다.
다만 어떤 이름을 사용하느냐에 따라 장소에 들은 값을 바꾸는 행위를 허락하느냐 안 하느냐의 차이입니다.

rra = 10 ;
ra = 10 ;

두 다 같은 장소에 10이라는 값을 넣으려는 의도이나 컴파일러는 첫 번째만 허락하고 두 번째는 허락하지 않습니다.

익명 사용자의 이미지

댓글에 쓴 코드가 깨졌네요. 전부 원문에 있는 코드를 인용한 것이니 이를 참조하시면 됩니다.

shint의 이미지

용어가 좀 헛갈립니다. 저도 10년만에 오늘 처음 알았습니다.

변경자   데이터형   상수값
const   int       10
 
 
 
터보C 정복 책을 보면.
 
//--------------------------------------------
163p
지정자 (specifier)와 변경자 (modifier)
형지정자(type specifier)의 종류 12가지
1. char, int, float, double, void
2. short, long, signed, unsigned
3. struct specifier, union specifier
4. enum specifier
5. typedef name
 
 
//--------------------------------------------
164p에 기억부류지정자와 변경자는 총 17개 입니다.
기억부류 지정자(storage class specifier)
typedef, extern, static, register, auto
 
const, volatile
포인터 변경자(pointer modifier)
near, far, huge, _cs, _ds, _es, _ss
 
함수 변경자(function modifier)
interrupt
 
특수한 목적에 쓰이는 변경자
cdecl, pascal
 
 
//--------------------------------------------
731p ~ 733p
 
터보 파스칼에는 형지정 상수(typed constant) 라는 것이 있다.
const가 바로 그 파스칼의 형지정 상수와 유사한 새로운 데이터형을 만들어주는 변경자(modifier)이다.
 
const float pi = 3.141592;
*(float*)(&pi) = 20.0;
 
변환자를 사용하면. 값을 바꿀 수 있습니다.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

shint의 이미지

일부 예제와 내용에 오류가 있을 수 있으니.
정확한 내용은 책을 보거나. 컴파일이 되는 개발도구로 값을 확인해 보시기 바랍니다.

0. 동적 변수를 사용한 경우 - 코드 예제1
const 변환자 int 형 데이터에 상수값이 바뀌었습니다.

1. 고정 변수를 사용한 경우 - 코드 예제2
C++ 에서 (int*) 명시적 형변환과 const_cast()에 결과는 같았습니다.
하지만. 결과적으로 const 변환자 int 형 데이터에 상수값 20은 바뀌지 않았습니다.

3. C 에서 const 변환자에 상수값은 명시적 형변환으로 바꿀 수 있었습니다.
4. C++ 에서 const 변환자에 상수값이 명시적 형변환으로 바뀌는것이 되는지는 모르겠습니다.

5. Visual C++ 컴파일러와 debug. gdb 등으로 어셈블리를 확인해보면.
보다 정확하게 알 수 있을것 같습니다. ㅡ_ㅡ;; 귀찮음...
6. C 에서의 T 는 배열을 의미했었습니다.

//http://codepad.org 에서 소스 코드를 컴파일하고. 확인해 보실 수 있습니다.

//-----------------------------------------------------------
//코드 예제1.
//메모리 할당을 통해서 적용된 경우.

#include
using namespace std;

//http://blog.naver.com/boomber13?Redirect=Log&logNo=80200032264
//http://en.wikipedia.org/wiki/Operator_delete
int main()
{
int i=0;

//변경자 데이터형 변수 int가 10개인 배열
const int* N = new int[10];
for(i=0; i<10; i++)
{
cout << *(N+i) << " ";
}
cout << endl;

//데이터형 변수인 int형 포인터
int* pN;

//
pN = (int*)(N);
pN = const_cast(N);

for(i=0; i<10; i++)
{
//error: assignment of read-only location 잘못 참조 되었을 경우 발생하는 메시지
// *(N+i) = i;
// cout << *(N+i) << " ";
*(pN+i) = i;
cout << *(pN+i) << " ";
}
cout << endl;

cout << N << '\t' << &N << '\t' << *N << endl;
cout << pN << '\t' << &pN << '\t' << *pN << endl;

delete [] N;
}

//-----------------------------------------------------------
//코드 예제2.
//고정 변수를 사용한 경우

//https://www.ics.com/designpatterns/book/staticcast.html

#include
using namespace std;

int main() {
const int N = 22;
int* pN;
pN = (int*)(&N);
pN = const_cast(&N);
cout << N << '\t' << &N << endl;
cout << *pN << '\t' << pN << '\t' << *(&pN) << '\t' << &(*pN) << '\t' << &pN << endl;
*pN = 33;
cout << N << '\t' << &N << endl;
cout << *pN << '\t' << pN << '\t' << *(&pN) << '\t' << &(*pN) << '\t' << &pN << endl;
}

//pN에 값인 *pN은 33으로 바뀌었지만.
//주소가 참조된 N의 값은 바뀌지 않았다.
//이것은 두값을 바꾸었지만. const 값은 바뀌지 않았슴을 이야기 한다.

//const int N = 20; 에서 const를 빼면. 둘다 33이 된다.

//-----------------------------------------------------------
//코드 예제3.
//고정 변수를 레퍼런스 참조한 경우
#include
using namespace std;

int main()
{
const int a = 10 ;
int &ra = const_cast(a) ;
cout << a << '\t' << &a << '\t' << endl;
cout << ra << '\t' << &ra << '\t' << endl;

ra = 20 ;
cout << a << '\t' << &a << '\t' << endl;
cout << ra << '\t' << &ra << '\t' << endl;

}

//코드 예제 2와 3의 결과가 같습니다.
//10 0xffe12778
//10 0xffe12778
//10 0xffe12778
//20 0xffe12778

//-----------------------------------------------------------
//코드 예제4.
//메모리 할당이 0인 경우. 해제를 하지 않으면 된다. ㅡ_ㅡ;;

#include
using namespace std;

int main()
{
const int * pa = new int[1];

int * pb = const_cast(pa);
cout << pa << '\t' << &pa << '\t' << *pa << endl;
cout << pb << '\t' << &pb << '\t' << *pb << endl;

*pb = 10;
cout << pa << '\t' << &pa << '\t' << *pa << endl;
cout << pb << '\t' << &pb << '\t' << *pb << endl;

//memory clobbered past end of allocated block
//0일경우. 메모리 해제시 오류 메시지

//new int[1]; 은 delete가 됨
// delete [] pa;
// delete pa;
}

각종 설명
When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?
http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used

기억부류 지정자(storage class specifier)
http://blog.naver.com/semi7623?Redirect=Log&logNo=100005635904

[Visual C++][강좌&팁] C++ 이야기 - [1] 캐스트 연산자 const_cast
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7777&ref=7777

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

HDNua의 이미지

북마크합니다.

저는 이렇게 생각했습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.