C에서 문자열 리터럴의 "수명"
다음 함수로 반환된 포인터는 액세스할 수 없는 것이 아닙니까?
char *foo(int rc)
{
switch (rc)
{
case 1:
return("one");
case 2:
return("two");
default:
return("whatever");
}
}
따라서 C/C++에서 국소 변수의 수명은 사실상 함수 내에서만 가능합니다. 그렇죠?그 말은, 그 다음에char* foo(int)
종료, 반환되는 포인터는 더 이상 아무 의미가 없습니다, 그렇죠?
저는 지역 변수의 수명에 대해 약간 혼란스럽습니다.무엇이 좋은 설명입니까?
예, 로컬 변수의 수명이 범위 내에 있습니다({
,}
생성되는 위치입니다.
로컬 변수에는 자동 또는 로컬 저장소가 있습니다.자동: 작성된 범위가 종료되면 자동으로 삭제됩니다.
그러나 여기에 있는 것은 구현 정의 읽기 전용 메모리에 할당된 문자열 리터럴입니다.문자열 리터럴은 로컬 변수와 다르며 프로그램 수명 동안 활성 상태를 유지합니다.그들은 정적인 지속 시간을 가집니다.
경고의 말!
그러나 문자열 리터럴의 내용을 수정하려는 시도는 정의되지 않은 동작(UB)입니다.사용자 프로그램은 문자열 리터럴의 내용을 수정할 수 없습니다.
따라서 항상 다음을 사용하는 것이 좋습니다.const
문자열 리터럴을 선언하는 동안.
const char*p = "string";
대신에,
char*p = "string";
에서는 사, C++에, 없는 문자열 .const
아 지 만 문 리 을 럴 다 같 선 이 언 그 const
에서는 컴파일러가 두 번째 경우 문자열 리터럴을 수정하려고 할 경우 일반적으로 경고를 제공한다는 이점을 제공합니다.
샘플 프로그램:
#include<string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[]="Sample string";
strcpy(str1,source); // No warning or error just Undefined Behavior
strcpy(str2,source); // Compiler issues a warning
return 0;
}
출력:
cc1: 경가오로처리
prog.c: 'prog.c':
'인수 대상 .c:9에서 됩니다. c:9: 'strcpy'의 경우 1번째로 한정자가 삭제됩니다.
컴파일러는 두 번째 경우에 대해 경고하지만 첫 번째 경우에는 경고하지 않습니다.
여기서 몇 명의 사용자가 묻는 질문에 답하려면 다음과 같이 하십시오.
필수 리터럴은 어떻게 처리됩니까?
즉, 다음 코드가 유효한가요?
int *foo()
{
return &(2);
}
정답은 이 코드가 올바르지 않다는 것입니다.형식이 잘못되어 컴파일러 오류가 발생합니다.
다음과 같은 것:
prog.c:3: error: lvalue required as unary ‘&’ operand
문자열 리터럴은 l-값입니다. 즉, 문자열 리터럴의 주소를 사용할 수는 있지만 내용을 변경할 수는 없습니다.
그러나 다른 리터럴(int
,float
,char
등)은 r-값이며(C 표준은 이들에 대한 표현식의 값을 사용함) 주소를 전혀 취할 수 없습니다.
[참조 1]C99 표준 6.4.5/5 "문자열 리터럴 - 의미론":
변환 단계 7에서는 문자열 리터럴 또는 리터럴에서 발생하는 각 멀티바이트 문자 시퀀스에 바이트 또는 값 0 코드가 추가됩니다.그런 다음 멀티바이트 문자 시퀀스를 사용하여 시퀀스를 포함하기에 충분한 정적 저장 기간 및 길이의 배열을 초기화합니다.문자열 리터럴의 경우 배열 요소는 char 유형을 가지며 다중 바이트 문자 시퀀스의 개별 바이트로 초기화됩니다. 와이드 문자열 리터럴의 경우 배열 요소는 wchar_t 유형을 가지며 와이드 문자 시퀀스로 초기화됩니다.
요소의 값이 적절한 경우 이러한 배열이 구별되는지 여부는 지정되지 않습니다.프로그램이 이러한 배열을 수정하려고 하면 동작이 정의되지 않습니다.
유효합니다.문자열 리터럴은 정적 저장 기간을 가지므로 포인터가 매달리지 않습니다.
C의 경우, 6.4.5항, 6항에 규정되어 있습니다.
변환 단계 7에서는 문자열 리터럴 또는 리터럴에서 발생하는 각 멀티바이트 문자 시퀀스에 바이트 또는 값 0 코드가 추가됩니다.그런 다음 멀티바이트 문자 시퀀스를 사용하여 시퀀스를 포함하기에 충분한 정적 저장 기간 및 길이의 배열을 초기화합니다.
섹션 2.14.5의 C++의 경우, 8-11항:
및 은 협 .8 UTF-8은 UTF-8과의 사이에 있습니다.은 " n 좁은 리문열유 "array" 입니 n 다는형" 입니다.
const char
여기서 n은 아래 정의된 문자열의 크기이며 정적 저장 기간(3.7)을 갖습니다.9 u로 시작하는 문자열 리터럴은 다음과 같습니다.
u"asdf"
입니다.char16_t
문자열 리터럴. Achar16_t
리터럴은 " n 문열리자 "array" "array" 입니다.const char16_t
여기서 n은 아래 정의된 문자열의 크기입니다. n은 정적 저장 기간을 가지며 지정된 문자로 초기화됩니다.는 둘 의 c-char를 할 수 .char16_t
서로게이트 쌍 형식의 문자입니다.10 U로 시작하는 문자열 리터럴(예:
U"asdf"
이다.char32_t
문자열 리터럴. Achar32_t
문자열 리터럴에 "array" 형식이 n개 있습니다.const char32_t
여기서 n은 아래 정의된 문자열의 크기입니다. n은 정적 저장 기간을 가지며 지정된 문자로 초기화됩니다.L로 로, 를 들어 L 작 시 문 리 터 다 같 습 과 니 음 다 은 럴 열 자 하 는 로 ▁that ▁11 니 같 다 습 ▁as ▁11 ▁l ▁literal ▁such 과 다 ▁string
L"asdf"
는 넓은 문자열 리터럴입니다.은 " n 넓은문리터는유의럴"array n다입니" 입니다.const wchar_t
여기서 n은 아래 정의된 문자열의 크기입니다. n은 정적 저장 기간을 가지며 지정된 문자로 초기화됩니다.
문자열 리터럴은 전체 프로그램에 대해 유효하므로(스택이 아닌 할당되지 않음) 유효합니다.
또한 문자열 리터럴은 읽기 전용이므로 (좋은 스타일을 위해) 변경해야 합니다.foo
const char *foo(int)
예, 유효한 코드입니다. 아래 사례 1을 참조하십시오.적어도 다음과 같은 방법으로 함수에서 C 문자열을 안전하게 반환할 수 있습니다.
const char*
수 할 수 .수정할 수 없으며 호출자가 해제할 수 없습니다.아래에 설명된 해제 문제 때문에 기본값을 반환하는 데는 거의 유용하지 않습니다.함수 포인터를 실제로 어딘가에 전달해야 하므로 문자열을 반환하는 함수가 필요하다면 말이 될 수 있습니다.char*
또는const char*
정적 문자 버퍼에 연결합니다.호출자에 의해 해제되지 않아야 합니다.수정할 수 있지만(항상 그렇지 않은 경우 호출자가 수정하거나 반환하는 함수를 통해) 반환하는 함수는 여러 버퍼를 가질 수 없으므로 스레드 세이프가 아니며(쉽게) 호출자가 반환된 값을 다시 호출하기 전에 복사해야 할 수도 있습니다.char*
할된버에퍼로malloc
수정할 수 있지만 일반적으로 호출자가 명시적으로 해제해야 하며 힙 할당 오버헤드가 있어야 합니다.strdup
이 유형입니다.const char*
또는char*
함수에 인수로 전달된 버퍼로, 반환된 포인터가 인수 버퍼의 첫 번째 요소를 가리킬 필요가 없습니다.그것은 버퍼/메모리 관리의 책임을 호출자에게 떠넘깁니다.많은 표준 문자열 함수가 이 유형입니다.
한 가지 문제는, 이것들을 하나의 기능으로 섞는 것이 복잡해질 수 있다는 것입니다.호출자는 반환된 포인터를 어떻게 처리해야 하는지, 유효한 포인터의 길이, 그리고 호출자가 포인터를 해제해야 하는지 알아야 하며 런타임에 이를 확인할 수 있는 (좋은) 방법이 없습니다.수 . 힙 합니다. 때때로 호출자가 필요로 하는 힙 할당 버퍼로 포인터를 반환합니다.free
그리고 때때로 호출자가 하지 말아야 하는 문자열 리터럴의 기본값에 대한 포인터. free
.
좋은 질문입니다.일반적으로 당신이 옳겠지만, 당신의 예는 예외입니다.컴파일러는 문자열 리터럴에 전역 메모리를 정적으로 할당합니다.따라서 함수에 의해 반환된 주소는 유효합니다.
이것이 C의 꽤 편리한 특징이지 않습니까?이 기능을 통해 프로그래머가 메시지가 저장된 메모리에 대해 걱정하지 않고 미리 작성된 메시지를 반환할 수 있습니다.
: 관찰 re: @asaelr 올른관찰바reconst
.
로컬 변수는 선언된 범위 내에서만 유효하지만, 해당 함수에서는 로컬 변수를 선언하지 않습니다.
에서 문자열 에 문자열 것과 마찬가지로 합니다.static
또는 전역 변수가 될 수 있습니다.
수행 중인 작업이 정의되지 않은 잘못된 작업일 수 있다는 우려가 있는 경우 컴파일러 경고를 표시하여 실제로 잘못된 작업이 있는지 확인해야 합니다.
str
문자열 리터럴이 상주하는 정적 주소를 가리키기 때문에 절대 달링 포인터가 되지 않습니다.
대부분 읽기 전용이며 로드될 때 프로그램 전체에 적용됩니다.
자유롭게 하거나 수정하려고 해도 메모리 보호 기능이 있는 플랫폼에 분할 오류가 발생합니다.
로컬 변수가 스택에 할당됩니다.함수가 완료되면 변수가 범위를 벗어나 코드에서 더 이상 액세스할 수 없습니다.그러나 해당 변수를 가리키도록 할당한 전역(또는 단순히 범위를 벗어나지 않음) 포인터가 있으면 해당 변수가 있었던 스택의 위치를 가리킵니다.다른 함수에서 사용하는 값이거나 의미 없는 값일 수 있습니다.
당신이 보여준 위의 예에서, 당신은 실제로 위를 호출하는 어떤 함수에도 할당된 포인터를 반환하고 있습니다.따라서 로컬 포인터가 되지 않습니다.또한 반환해야 하는 포인터의 경우 글로벌 세그먼트에 메모리가 할당됩니다.
언급URL : https://stackoverflow.com/questions/16470959/can-we-return-string-literal-in-c
'programing' 카테고리의 다른 글
Google Chrome에 대해 자동 로그온 사용자 인증을 활성화하는 방법 (0) | 2023.09.05 |
---|---|
달러(약)ready(함수:{}); 페이지 하단의 vs 스크립트 (0) | 2023.08.31 |
mariaDB에 사용할 cnf 파일을 지정하는 곳은 어디입니까? (0) | 2023.08.31 |
jQuery agax - statusCode() 콜백이 호출될 때 오류() 콜백 방지 (0) | 2023.08.31 |
Mariadb 드라이버 Aurora IAM 자격 증명 유형 액세스가 사용자에 대해 거부되었습니다(암호 사용: YES). (0) | 2023.08.31 |