문자열상수는 Rvalue아닌가요?

vani2의 이미지

주소연산자(&)에서 피연산자는 lvaue여야 합니다. (C++03 5.3.1/2).

왜냐하면, 영속적인 객체의 주소를 가지는 것은 괜찮지만, 임시적인 객체의 주소를 가지는 것은 굉장히 위험 하기 때문입니다.

출처 - http://scor7910.tistory.com/66

제가 아직 문자열상수에 대해서 제대로 된 이해를 못했는지는 모르겠지만..

일단 문자열상수는 실행파일 상수영역에 보관되고 있다면

char* c = "ㅁㄴㅇㄹ";

c라는 char*형 변수에 "ㅁㄴㅇㄹ"라는 문자열 상수의 번지를 대입하는 것으로 lvalue에 rvalue를 대입한것 아닌가요?

const char (*c)[9] = &"ㅁㄴㅇㄹ";

위 문서에 따르면 rvalue는 임시적인 값이므로 &연산자가 붙으면 안된다고 되어있는데

문자열은 예외라고 할 수 있나요?

winner의 이미지

기존 C code 들과의 호환성을 고려하여 결정된 사항으로 문자열 literal 은 문맥에 맞춰 pointer 로 변환될 때 const char* 가 아닌 char* 로 변환됩니다.

그러나 용어가 좀 잘못 사용되어 바로 잡자면 C++ 표준에서 lvalue 는 주소추출이 가능한 것이냐를 따지는 것으로 C 표준에서는 object 라는 단어를 사용합니다. l 이 left hand side 에서 나온 단어는 맞지만 이제는 locator 를 의미한다고 말하기도 하지요. 그러니까 대입연산자 좌측에 올 수 있느냐를 따지는 것은 아니라는 것입니다. 표준에 lvalue 를 정의해놓은 부분이 있을 것입니다.

문자열 literal 은 통상적으로 실행파일의 상수영역에 보관되는 것이 맞고, 따라서 영속객체라고 할 수 있습니다. 따라서 주소추출을 하는 것에 문제가 될 것이 없으며, 이것은 표준에서도 보장되는 것입니다.

vani2의 이미지

아 예외 상황이였군요.

그럼 주소추출이 가능하니

const lvalue라고 할 수 있나요?

winner의 이미지

하지만 그런 단어는 없습니다. 표준을 인용하시면서 다른 분들과 대화할 때 그런 단어를 쓰면 못 알아들을 겁니다.
그리고 문자열 literal 이 char* 로 변환되기 때문에 통상적으로 변환된 pointer 를 역참조해서 수정을 하는 code 가 compile 되는 것이 보통일텐데 물론 그런 code 를 작성하면 안됩니다. 좀더 정확히 말하자면 표준의 undefined 에 해당됩니다.
제가 알기로 lvalue 중에서 역참조해서 수정할 수 없는 것은 const 한정된 변수, 함수, 문자열 literal 이 있습니다. 이 가운데 문자열 literal 를 제외하고는 보통 역참조 후 수정하는 code 는 compile 이 실패되기 때문에 오류를 찾는 것은 어렵지 않을 겁니다.
따라서 문자열 literal 을 char* 변수에 대입하는 것은 비록 가능하나 통상적으로 const char* 에 대입하여 compile 단계에서 실수를 발견할 수 있는 방식을 쓰는 것이 권장됩니다.

아, 그런데 질문이 두개였다고 할 수 있는데 문자열 literal 그자체에 & 을 써서 const char(*)[n] 형식의 값을 만드는 것이 가능합니다만 유용한 경우는 제가 못 봤군요.

vani2의 이미지

아 그런가요..

저는 lvalue 종류가 두가지라고 알고있는데..

변경 가능한 lvalue와(non const)
변경 불가능한 lvaue(const)가 있다고 들었습니다.

이것이 표준이 아닌가요? 아니면 제가 착각하고 있는 것이 있을까요..

winner의 이미지

다만 modifiable 과 non-modifiable 로 표기하는게 보통이더군요.
http://en.wikipedia.org/wiki/Value_(computer_science)

vani2의 이미지

아하 그렇군요.

좋은 답변 감사드립니다.

익명 사용자의 이미지

문자열 상수(string literal)의 실체는 배열입니다.
배열이기 때문에 수식 안에서 쓰일때는
그 자신의 첫번째 주소를 가리키는 포인터 주소 값으로 변환이 일어나며,
&연산자의 피연산자로 이용될 때는 이 규칙에 예외가 적용됩니다.

따라서, &"str"이나 "str"이나 결과는 같습니다.

const char arr[] = "string";

const char *ps1 = arr;
const char *ps2 = &arr;

const char *ps3 = "string";
const char *ps4 = &"string";

C99 기준으로는, const char형이 아니고 char형인게 흥미로운 점인데,
대신 문자열 상수의 수정 금지에 대해서는 별개의 규칙을 가지고 있습니다.

If the program attempts to modify such an array, the behavior is
undefined.

저는 아마도 이것이, 문자열 상수를 const가 아닌 보통의 char * 형 포인터로 다루던
기존의 코드들과 관례 때문에,
이렇게 규칙을 따로 두게 된것이 아닌가 추측합니다.

C++은 어떤 식으로 되어 있는지 모르겠는데
나중에 찾아볼 기회가 있으면 또 리플을 달던가 하지요.

익명 사용자의 이미지

정신이 없는 가운데 썼더니 심각한 오류가 있네요.

"str" 이랑 같은건 &"str"[0] 입니다.

"str"과 &"str"은 가리키는 주소값은 같은데 가리키는 타입이 다릅니다.
따라서 위 코드에서 다음 두 줄은 경고나 에러가 뜰 겁니다.

const char *ps2 = &arr;

const char *ps4 = &"string";

이걸 &arr이나 &"string"[0] 으로 바꾸면 정상 코드가 됩니다.

vani2의 이미지

그렇군요 정확한 답변감사합니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.