programing

문자열 리터럴은 고정입니까?

javajsp 2023. 10. 21. 09:56

문자열 리터럴은 고정입니까?

내가 문자열 리터럴을 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 초안 표준(C89C11은 유사한 문구)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