조건부 연산자를 사용할 때 C는 문자열 연결을 허용하지 않는 이유는 무엇입니까?
다음 코드는 문제없이 컴파일됩니다.
int main() {
printf("Hi" "Bye");
}
다만, 이것은 컴파일 되지 않습니다.
int main() {
int test = 0;
printf("Hi" (test ? "Bye" : "Goodbye"));
}
그것의 이유는 무엇인가?
C11 규격 「5.1.1.2」의 「인접 스트링 리터럴의 연결:
인접한 문자열 리터럴 토큰이 연결됩니다.
변환 국면에서 발생합니다.한편, 다음과 같습니다.
printf("Hi" (test ? "Bye" : "Goodbye"));
에는 조건부 연산자가 포함되어 런타임에 평가됩니다.따라서 컴파일 시 변환 단계에서는 인접한 문자열 리터럴이 존재하지 않으므로 연결할 수 없습니다.구문이 잘못되었으므로 컴파일러에 의해 보고됩니다.
그 이유에 대해 좀 더 자세히 설명하자면, 전처리 단계에서 인접한 문자열 리터럴이 연결되어 단일 문자열 리터럴(토큰)로 표시됩니다.스토리지가 적절히 할당되고 연결된 문자열 리터럴은 단일 엔티티(1 문자열 리터럴)로 간주됩니다.
한편, 런타임 연결의 경우, 수신처는 연결된 문자열 리터럴을 보유하기에 충분한 메모리를 가지고 있어야 합니다.그렇지 않으면 예상되는 연결 출력에 액세스할 수 없습니다.스트링 리터럴의 경우 컴파일 시에 이미 메모리가 할당되어 있기 때문에, 원래의 컨텐츠에의 착신 입력에 맞추어 확장할 수 없습니다.즉, 연결된 결과를 단일 문자열 리터럴로 액세스(제시)할 수 없습니다.그래서 이 구문은 본질적으로 틀렸습니다.
참고로 런타임 문자열(리터럴이 아닌) 연결을 위해 두 문자열을 연결하는 라이브러리 함수가 있습니다.설명에는 다음과 같은 내용이 기재되어 있습니다.
char *strcat(char * restrict s1,const char * restrict s2);
strcat()는 "이러다"가 을 추가합니다.s2(종료하는 늘 문자를 포함한다)가 나타내는 문자열의 끝에 도달합니다.의 첫 번째 문자s2、 [ ].s1[...]
보면, '우리'는 '우리'는 '우리'는 '우리'는 '우리'가 아니라 '우리'는's1는 문자열이며 문자열 리터럴이 아닙니다.단, 의 내용으로서s2어떤 식으로도 변경되지 않습니다.문자열 리터럴일 수도 있어요
에는 'C'가 string은 type으로 됩니다. 문자열 리터럴은 다음과 같이 컴파일됩니다.char " "에 됨"char*포인터
C에서는 첫 번째 예시와 같이 컴파일 시에 인접 리터럴을 조합할 수 있습니다.C 컴파일러 자체는 문자열에 대한 지식이 있습니다.그러나 이 정보는 런타임에 존재하지 않으므로 연결이 발생할 수 없습니다.
컴파일 프로세스 중에 첫 번째 예는 다음과 같이 "번역"됩니다.
int main() {
static const char char_ptr_1[] = {'H', 'i', 'B', 'y', 'e', '\0'};
printf(char_ptr_1);
}
프로그램이 실행되기 전에 컴파일러에 의해 2개의 문자열이 하나의 정적 배열로 결합되는 방법에 유의하십시오.
그러나 두 번째 예는 다음과 같이 "변환"됩니다.
int main() {
static const char char_ptr_1[] = {'H', 'i', '\0'};
static const char char_ptr_2[] = {'B', 'y', 'e', '\0'};
static const char char_ptr_3[] = {'G', 'o', 'o', 'd', 'b', 'y', 'e', '\0'};
int test = 0;
printf(char_ptr_1 (test ? char_ptr_2 : char_ptr_3));
}
이것이 컴파일되지 않는 이유는 명확해야 합니다. 연산자 " " " "?는 컴파일 것은, 「실행, 한 「실행」으로서만 평가됩니다.이러한 "time"은 더 이상 존재하지 않고 단순하게만 평가됩니다.char " "에 의해 됨, " "char*포인터인접 문자열 리터럴과 달리 인접 문자 포인터는 구문 오류일 뿐입니다.
C기준(5.1.1.2 번역단계)에 준거
1 번역 구문 규칙 중 우선순위는 다음 단계로 지정됩니다.6)
- 인접한 문자열 리터럴 토큰이 연결됩니다.
그리고 그 후에야
- 토큰을 구분하는 공백 문자는 더 이상 의미가 없습니다.각 전처리 토큰은 토큰으로 변환된다.생성된 토큰은 구문 및 의미론적으로 분석되고 변환 단위로 변환됩니다.
이 구조에서는
"Hi" (test ? "Bye" : "Goodbye")
인접한 문자열 리터럴 토큰이 없습니다.따라서 이 구성은 유효하지 않습니다.
실행 시 선택할 컴파일 시간 문자열 상수를 두 분기 모두 생성하려면 매크로가 필요합니다.
#include <stdio.h>
#define ccat(s, t, a, b) ((t)?(s a):(s b))
int
main ( int argc, char **argv){
printf("%s\n", ccat("hello ", argc > 2 , "y'all", "you"));
return 0;
}
문자열 리터럴 연결은 컴파일 시 프리프로세서에 의해 실행됩니다.로 인해 이 값을 할 수 방법은 없습니다.test이는 프로그램이 실제로 실행될 때까지 알 수 없습니다.따라서 이러한 문자열 리터럴은 연결할 수 없습니다.
일반적으로 컴파일 시에 알려진 값에 대해서는 이와 같은 구성이 없기 때문에 C 표준은 자동 연결 기능을 가장 기본적인 경우, 즉 문자 그대로 리터럴이 서로 일치할 때에만 제한하도록 설계되었습니다.
그러나 이 제한에 대해 그렇게 표현하지 않았거나 제한이 다르게 구성되었다고 해도, 연결을 런타임 프로세스로 만들지 않고는 여전히 실현이 불가능합니다.그리고 이를 위해 우리는 다음과 같은 도서관 기능을 가지고 있다.strcat.
그것의 이유는 무엇인가?
3진 연산자를 사용하는 코드는 조건부로 두 문자열 리터럴 중 하나를 선택합니다.이것은 알려진 상태 또는 알려지지 않은 상태에 관계없이 컴파일 시 평가될 수 없으므로 컴파일할 수 없습니다.심지어 이 진술도printf("Hi" (1 ? "Bye" : "Goodbye"));컴파일되지 않습니다.이유는 위의 답변에 자세히 설명되어 있습니다.컴파일하기 위해 유효한 3진 연산자를 사용하여 이러한 스테이트먼트를 작성하는 또 다른 가능성에는 포맷태그와 3진 연산자 스테이트먼트의 결과도 포함됩니다.printf그때도printf()인쇄물은 실행 시 및 실행 시에만 이러한 문자열을 "연결"한 듯한 인상을 줄 수 있습니다.
#include <stdio.h>
int main() {
int test = 0;
printf("Hi %s\n", (test ? "Bye" : "Goodbye")); //specify format and print as result
}
인printf("Hi" "Bye");컴파일러가 단일 배열로 만들 수 있는 연속된 두 개의 char 배열이 있습니다.
인printf("Hi" (test ? "Bye" : "Goodbye"));배열이 하나 있고 그 뒤에 char(첫 번째 요소에 대한 포인터로 변환된 배열)로의 포인터가 있습니다.컴파일러가 배열과 포인터를 병합할 수 없습니다.
printf 함수의 파라미터 리스트는 다음과 같기 때문에 컴파일되지 않습니다.
(const char *format, ...)
그리고.
("Hi" (test ? "Bye" : "Goodbye"))
파라미터 리스트에 맞지 않습니다.
gcc는 그것을 이해하려고 한다.
(test ? "Bye" : "Goodbye")
는 파라미터 리스트이며 "Hi"는 함수가 아니라고 불평합니다.
질문에 답하려면 printf의 정의에 대해 살펴보겠습니다.함수 printf는 const char*를 인수로 예상합니다."Hi"와 같은 문자열 리터럴은 const char*이지만 다음과 같은 표현입니다.(test)? "str1" : "str2" char에 컴파일가 const char*에 할 수 있습니다.이러한 식의 결과는 실행 시에만 발견되기 때문에 컴파일 시 미확정이기 때문에 컴파일러가 불만을 제기할 수 있습니다. 이것은 하게 잘 합니다.printf("hi %s", test? "yes":"no")
언급URL : https://stackoverflow.com/questions/37259472/why-does-c-not-allow-concatenating-strings-when-using-the-conditional-operator
'programing' 카테고리의 다른 글
| Android Studio 콘솔에 인쇄하는 방법 (0) | 2022.07.10 |
|---|---|
| v-radio 레이블에서 HTML을 설정하는 방법 (0) | 2022.07.10 |
| Vuex Axios 호출이 422 응답을 처리할 수 없음 (0) | 2022.07.10 |
| 새 날짜 시간 API를 사용하여 날짜 형식 지정 (0) | 2022.07.10 |
| Ubuntu에서 Java 환경 경로 설정 방법 (0) | 2022.07.10 |