문자열 리터럴은 고정입니까?
내가 문자열 리터럴을 a에 할당해도 GCC와 Clang 모두 불평하지 않습니다.char*
, 많은 현학적 옵션을 사용할 때에도 (-Wall -W -pedantic -std=c99
):
char *foo = "bar";
그들이 (물론) 내가 일을 맡긴다면 불평을 할 것입니다.const char*
에 이르기까지char*
.
이것은 문자열 리터럴이 다음과 같은 것으로 간주된다는 것을 의미합니까?char*
거 요? 그래야만 하는 거 아닌가요?const char*
그들이 수정된다면 그것은 정의된 행동이 아닙니다!
그리고 (상관없는 질문) 명령줄 매개 변수(즉:argv
: 문자열 리터럴의 배열로 간주됩니까?
그들은 타입입니다.char[N]
어디에N
는 종결자를 포함한 문자의 수 입니다.\0
. 그래서 네, 당신은 그들을 지정할 수 있습니다.char*
, 그러나 여전히 그들에게 편지를 쓸 수 없습니다(효과는 정의되지 않습니다).
Wrtargv
문자열에 대한 포인터 배열을 가리킵니다.이러한 문자열은 명시적으로 수정할 수 있습니다.변경할 수 있으며 마지막으로 저장된 값을 보유해야 합니다.
완성을 위해 섹션의 C99 초안 표준(C89 및 C11은 유사한 문구)6.4.5
문자열 리터럴 5항은 다음과 같이 말합니다.
[...]값 0의 바이트 또는 코드는 문자열 리터럴 또는 리터럴에서 나오는 각 멀티바이트 문자 시퀀스에 추가됩니다.그런 다음 멀티바이트 문자 시퀀스를 사용하여 정적 저장 기간 및 길이 배열을 초기화하여 시퀀스를 포함하기에 충분합니다.문자열 리터럴의 경우 배열 요소는 char 형식을 가지며 멀티바이트 문자 시퀀스의 개별 바이트로 초기화됩니다;[...]
따라서 문자열 리터럴은 정적 저장 기간(프로그램의 수명이 지속됨)을 가지며, 유형은char[]
(아니오)char *
및 그는 0이 및 그 길이는 0이 추가된 문자열 리터럴의 크기입니다.*6'항은 다음과 같이 말합니다.
프로그램이 이러한 배열을 수정하려고 하면 동작이 정의되지 않습니다.
따라서 문자열 리터럴을 수정하려고 시도하는 것은 정의되지 않은 동작입니다.const
.
에 관하여argv
구간별로5.1.2.2.1
프로그램 시작 단락 2는 다음과 같이 말합니다.
이를 선언할 경우 주 기능에 대한 매개 변수는 다음과 같은 제약 조건을 따라야 합니다.
[...]
- argc 및 argv 매개변수 및 argv 배열에서 지시하는 문자열은 프로그램에서 수정할 수 있어야 하며, 프로그램 시작과 프로그램 종료 사이에 마지막으로 저장된 값을 유지해야 합니다.
그렇게argv
문자열 리터럴의 배열로 간주되지 않으며 내용을 수정해도 좋습니다.argv
.
으로.-Wwrite-strings
다음 옵션을 사용할 수 있습니다.
warning: initialization discards qualifiers from pointer target type
이 옵션과 관계없이 GCC는 리터럴을 읽기 전용 메모리 섹션에 넣을 것입니다.-fwritable-strings
(그러나 이 옵션은 최근 GCC 버전에서 제거되었습니다.)
명령줄 매개 변수는 일정하지 않으며 일반적으로 스택에 존재합니다.
(죄송합니다만, 이 질문은 다음과 같이 태그가 지정되어 있습니다.c
,것은 아니다.c++
제 이 것 같습니다 아마도 제 대답은 결국 이 질문과 그다지 관련이 없는 것 같습니다!)
문자열 리터럴이 완전하지 않습니다.const
아니면not-const
, 문학자들을 위한 특별한 이상한 규칙이 있습니다.
(요약: 리터럴은 다음과 같이 참조 배열로 취할 수 있습니다.foo( const char (&)[N])
그리고 non-const 배열로 사용할 수 없습니다.그들은 부패하기를 선호합니다.const char *
. 지금까지는, 그러니까 그들이const
. 하지만 문학자들이 붕괴할 수 있는 특별한 유산 규칙이 있습니다.char *
아래의 실험을 참조하십시오.
(다음 실험은 clang3에서 수행함).3 와 함께-std=gnu++0x
인 것 같습니다 혹시 이것이 C++11 문제인 것은 아닐까요?아니면 클랑에 특화된 건가요?어느 쪽이든 이상한 일이 벌어지고 있습니다.)
처음에 문학은const
:
void foo( const char * ) { std::cout << "const char *" << std::endl; }
void foo( char * ) { std::cout << " char *" << std::endl; }
int main() {
const char arr_cc[3] = "hi";
char arr_c[3] = "hi";
foo(arr_cc); // const char *
foo(arr_c); // char *
foo("hi"); // const char *
}
두 어레이는 예상대로 작동하여 다음과 같은 사실을 입증합니다.foo
우리에게 그 포인터가const
그렇지 않으면.그리고나서"hi"
선택합니다.const
의 버전foo
. 그래서 그것이 해결되는 것 같습니다: 문학자들은.const
... 그렇지 않습니까?
하지만, 제거하면.void foo( const char * )
그러면 이상해집니다.첫번째로 전화는foo(arr_c)
컴파일 시 오류가 발생하여 실패합니다.예상됩니다.하지만 문자 그대로의 호출(foo("hi")
작동합니다는 비정규 통화를 통해 작동합니다.
그래서, 문학자들은 그들보다 더 엄격합니다.arr_c
(왜냐하면 그들은 그들에게 부패하기를 원하기 때문입니다.const char *
,와는 달리arr_c
. 하지만 문학자들은 보다 덜 엄격합니다.arr_cc
왜냐하면 그들은 기꺼이 부패하기 때문입니다.char *
필요하면
(클랑은 붕괴하면 경고를 합니다.char *
).
하지만 썩어가는 건?단순화를 위해 피합시다.
대신 참고로 배열을 foo에 넣어보겠습니다.이를 통해 보다 '직관적'인 결과를 얻을 수 있습니다.
void foo( const char (&)[3] ) { std::cout << "const char (&)[3]" << std::endl; }
void foo( char (&)[3] ) { std::cout << " char (&)[3]" << std::endl; }
이전과 마찬가지로 리터럴과 컨스트 배열 (arr_cc
) const 버전을 사용하고 non-const 버전은 다음과 같이 사용합니다.arr_c
. 그리고 만약 우리가 삭제한다면.foo( const char (&)[3] )
, 그러면 우리는 둘 다 오류가 생깁니다.foo(arr_cc);
그리고.foo("hi");
. 간단히 말해서, 포인터 붕괴를 피하고 대신 참조-대-어레이를 사용하면 리터럴은 마치 그들이 그런 것처럼 행동합니다.const
.
템플릿?
템플릿에서 시스템은 다음과 같이 추론합니다.const char *
대신에char *
그리고 당신은 그것에 대해 "stuck"입니다.
template<typename T>
void bar(T *t) { // will deduce const char when a literal is supplied
foo(t);
}
그래서 기본적으로, 문자 그대로의 사람은const
당신이 직접 a를 초기화하는 특별한 경우를 제외하고는 항상char *
문자 그대로
종류와 내용은 요하네스의 대답이 맞습니다.그러나 그 외에도 문자열 리터럴의 내용을 수정하는 것은 정의되지 않은 동작입니다.
에 대한 당신의 질문과 관련하여.argv
:
매개 변수 argc 및 argv와 argv 배열이 가리키는 문자열은 프로그램에 의해 수정 가능해야 하며, 프로그램 시작과 프로그램 종료 사이에 마지막으로 저장된 값을 유지해야 합니다.
C89와 C99 모두에서 문자열 리터럴은 유형입니다.char *
(역사적인 이유로, 제가 알기로는.한 가지를 수정하려고 하면 정의되지 않은 동작이 발생하는 것이 맞습니다.GCC에는 특정 경고 플래그 -Write-strings(일부가 아님)가 있습니다.-Wall
이를 실행하려고 하면 경고를 받게 됩니다.
에 관해서는argv
, 인수는 당신의 프로그램의 주소 공간에 복사되고, 당신의 주소 공간에서 안전하게 수정될 수 있습니다.main()
기능.
편집: 헉, 가지고 있었습니다.-Wno-write-strings
실수로 복사한경고 플래그의 올바른(긍정적) 형식으로 업데이트됩니다.
문자열 리터럴에 형식 형식이 있습니다.char []
그러나 의미형.const char []
. 순수주의자들은 이것을 싫어하지만, "왜 내 프로그램이 충돌하는가?!?"라는 질문으로 많은 신입들을 SO로 데려오는 것을 제외하고는 이것은 일반적으로 유용하고 무해합니다.
이들은 constchar*이지만, const가 존재하기 전에 존재했던 레거시 코드에 대해 char*에 할당하는 특정 제외 사항이 있습니다.명령줄 인수는 문자 그대로가 아니라 런타임에 생성됩니다.
언급URL : https://stackoverflow.com/questions/4493139/are-string-literals-const
'programing' 카테고리의 다른 글
jQuery - 파일 입력에서 파일을 선택했는지 여부를 탐지합니다. (0) | 2023.10.21 |
---|---|
왜 우리는 공허함 이외의 다른 점들을 가지고 있는 거지? (0) | 2023.10.21 |
H2 및 Oracle 호환성 문제 (0) | 2023.10.21 |
CSS3 애니메이션으로 눈 깜빡임 태그 따라하기 (0) | 2023.10.21 |
Visual Studio 2015 Community의 SQL Server Object Explorer에 LocalDB를 추가하는 방법은? (0) | 2023.10.21 |