C에서 "a"! = "a"는 왜입니까?


110
void main() {
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

출력되는 이유는 무엇 No, not equal입니까?


100
void main??? Ew ...
Paul R

47
임베디드 C 컴파일러는 리턴 코드를 제공 할 운영 체제가 없을 수 있으므로 void main ()을 허용합니다.
Jeanne Pindar 2011 년

26
이와 같은 질문이 어떻게 그렇게 자주 찬성 될 수 있습니까? 그다지 흥미롭지 않습니다 ... 내 말은, 문자열은 배열이고 배열은 포인터라는 것은 C에서 정말 오래된 모자입니다.
Felix Dombek 2011 년

64
@Felix,이 질문은 언어를 처음 접하는 사람들의 일반적인 혼란을 해결하기 위해 간결하게 작성된 질문입니다. 따라서 전문가만을위한 것이 아닙니다. 초보자도 마찬가지입니다. 이와 같은 대상 질문은 미래에 초보자를 추천하는 데 유용합니다.
bdonlan 2011 년

37
@Felix : 당신은 틀 렸습니다. 배열은 포인터가 아닙니다
John Dibling 2011 년

답변:


209

비교하는 것은 서로 다른 위치에 저장된 서로 다른 문자열에 대한 두 개의 메모리 주소입니다. 그렇게하는 것은 본질적으로 다음과 같습니다.

if(0x00403064 == 0x002D316A) // Two memory locations
{
    printf("Yes, equal");
}

다음 코드를 사용하여 두 문자열 값을 비교합니다.

#include <string.h>

...

if(strcmp("a", "a") == 0)
{
    // Equal
}

또한 "a" == "a"컴파일러에 따라 실제로 true를 반환 할 수 있으며, 컴파일 시간에 동일한 문자열을 하나로 결합하여 공간을 절약 할 수 있습니다.

두 문자 값 (포인터가 아님)을 비교할 때는 숫자 비교입니다. 예를 들면 :

'a' == 'a' // always true

12
GCC는 옵션이 있습니다 -fmerge-constants-fno-merge-constants일부 GCCs에 상수 병합에 관계없이 항상 해당 옵션의 설정되어 있는지 보이지만, 활성화 / 비활성화 문자열과 번역 단위에서 병합 부동 소수점 상수를.
Adam Rosenfield 2011 년

2
"a"대신 'a'를 사용하면 작동합니다. 첫 번째는 실제로 숫자 값인 문자입니다.
GolezTrol 2011 년

@GolezTrol : C에서 리터럴 'a'에는 실제로 int유형이 있습니다. :-) 또한 포인터는 숫자 값일 필요가 없습니다.
Bastien Léonard 2011 년

int숫자도 그렇죠? 하지만 나는 문자가 바이트라고 생각했습니다. Int는 4 바이트입니다. 포인터 자체도 정수입니다. 여기에는 데이터 (실제로 숫자 일 필요가없는 데이터)의 주소가 포함됩니다.
GolezTrol 2011 년

'a' == 'A' // not true... MySQL은 다를 것을 간청합니다.
Steven

52

나는 파티에 조금 늦었지만 어쨌든 대답 할 것입니다. 기술적으로는 동일한 부분이지만 약간 다른 관점에서 보면 (아래 C 용어) :

C에서, 상기 식은 "a"나타낸다 문자열 리터럴 정적 이름 배열, const char이들의 길이, - 어레이는 문자로 구성 'a'하고 '\0'- 종단 NULL 문자는 문자열의 끝에 신호를 보낸다.

그러나 C에서는 배열을 값으로 함수에 전달하거나 값을 할당 할 수없는 것과 같은 방식으로 ( 초기화 후 ) ==배열에 대해 오버로드 된 연산자가 없으므로 직접 비교할 수 없습니다. 치다

int a1[] = {1, 2, 3};
int a2[] = {3, 4, 5};
a1 == a2 // is this meaningful? Yes and no; it *does* compare the arrays for
         // "identity", but not for their values. In this case the result
         // is always false, because the arrays (a1 and a2) are distinct objects

는 IF ==배열을 비교되지 않으며, 실제로 다음, 무엇을해야합니까? C에서 거의 모든 컨텍스트 (이 것을 포함하여)에서 배열 은 포인터 ( 배열 의 첫 번째 요소를 가리킴)붕괴 하고 포인터를 비교하여 예상대로 수행합니다. 이렇게하면 효과적으로

"a" == "a"

실제로 이름이 지정되지 않은 두 배열의 첫 번째 문자 주소를 비교하고 있습니다 . C 표준에 따르면 비교는 참 또는 거짓 (즉, 1 또는 0)을 산출 할 수 있습니다. "a"s는 실제로 동일한 배열 또는 완전히 관련되지 않은 두 배열을 나타낼 수 있습니다. 기술적 인 측면에서 결과 값은 지정되지 않습니다. 즉, 비교가 허용되지만 (즉, 정의 되지 않은 동작 이나 구문 오류가 아님) 두 값이 유효하고 구현 (컴파일러)이 실제로 발생할 일을 문서화 할 필요가 없습니다.

다른 사람들이 지적했듯이 "c 문자열"(즉, 널 문자로 끝나는 문자열)을 비교하려면 strcmp표준 헤더 파일에 있는 편의 함수를 사용 합니다 string.h. 함수는 0동일한 문자열 에 대한 반환 값 을 갖습니다. 0연산자`! ´를 사용하는 대신 반환 값을 명시 적으로 비교하는 것이 좋습니다 .

strcmp(str1, str2) == 0 // instead of !strcmp(str1, str2)

47

C99 (섹션 6.4.5 / 6)에 따름

문자열 리터럴

요소에 적절한 값이있는 경우 이러한 배열이 구별되는지 여부는 지정되지 않습니다 .

따라서이 경우 두 가지 모두 "a"구별 되는지 여부는 지정되지 않습니다. 최적화 된 컴파일러 "a"는 읽기 전용 위치에 하나 를 유지할 수 있으며 두 참조 모두이를 참조 할 수 있습니다.

여기 에서 gcc의 출력을 확인 하십시오.


19

두 개의 별도 const char*의 포인터 이기 때문에 실제 값이 없습니다. 0x019181217 == 0x0089178216당연히 NO를 반환하는 것과 같은 것을 말하고 있습니다.

strcmp()대신 사용==


7
문자열 리터럴은 포인터가 아니라 배열입니다. 그러나 그들은 비교에 대한 포인터로 붕괴됩니다.
GManNickG 2011 년

사실 @Gman, 미안 그에 정말 선택 없었던 :) 그것을 잊지하는 경향이
Antwan 반 Houdt

9

간단히 말해, C에는 내장 문자열 비교 연산자가 없습니다. 이런 식으로 문자열을 비교할 수 없습니다.

대신 strcmp ()와 같은 표준 라이브러리 루틴을 사용하거나 문자열의 각 문자를 반복하는 코드를 작성하여 문자열을 비교합니다.

C에서 큰 따옴표로 묶인 텍스트 문자열은 문자열에 대한 포인터를 반환합니다. 귀하의 예는 포인터를 비교하고 있으며 분명히 두 버전의 문자열이 다른 주소에 존재합니다.

그러나 예상대로 문자열 자체를 비교하지 않습니다.


3

포인터.

첫 번째 "a"는 널로 끝나는 ASCII 문자열에 대한 포인터입니다.

두 번째 "a"는 다른 널 종료 ASCII 문자열에 대한 포인터입니다.

32 비트 컴파일러를 사용하는 경우 "a"=="a"-4. 그래도 tcc / Win32로 시도했지만 "a"=="a"-2. 아 글쎄 ...


6
문자열이 4 바이트 경계로 정렬되는 이유는 무엇입니까? 그들은 int가 아닙니다. 2는 내가 예상했던 것입니다 (컴파일러가 그것들을 병합하지 않는 경우). 각 문자열은 널 종료자를 포함하여 2 바이트 길이이기 때문입니다.
Sergei Tachenov 2011 년

예를 들어 어느 정도 정렬하면 strcmp한 번에 여러 바이트를 실행할 수 있습니다. 일부 컴파일러는이를 수행하고 일부는 수행하지 않으며 일부는 최소값보다 긴 문자열에 대해서만 수행합니다.
zwol

@Zack : 실제로 비교하기 전에 문자열의 길이를 어떻게 알 수 있습니까?
Joachim Sauer

일부 컴파일러는 최소값보다 긴 문자열을 정렬합니다.
zwol

1

두 개의 메모리 주소를 비교하고 있으므로 결과가 항상 사실 인 것은 아닙니다. 해봤 어 if('a' == 'a'){...}?


1

이 질문은 모든 초보자를위한 아주 좋은 설명의 흔적을 설정합니다 ....
또한 그것에 기여하겠습니다 .....

위의 모든 사람들이, 왜 그런 출력을 얻는 지 설명했습니다.

지금 당신이 당신의 음식물을 원한다면. "예 같음"을 인쇄하려면

어느 쪽이든 사용

if(strcmp("a", "a") == 0)
{

}

또는
"a"를 문자열로 사용하지 말고 문자로 사용하십시오 ....

if('a'=='a')  
{  
printf ("yes Equal");  
}  

C 문자는 1 바이트 짧은 정수입니다 .......


문자는 1 바이트 만 차지하지만과 같은 문자 리터럴 'a'은 실제로 정수입니다.
Spidey

0

일부 컴파일러에는 모든 상수 문자열이 동일한 주소를 갖도록 강제하는 데 사용할 수있는 '문자열 병합'옵션이 있습니다. 당신이을 사용하면 "a" == "a"될 것이다 true.


0

문자 간의 비교가 항상 작은 따옴표로되어있는 경우, 예 :

if('a' == 'a')

C는 다음과 같은 문자열 비교를 지원할 수 없습니다. "abc" == "abc"

끝났어 strcmp("abc","abc")


-5

이 사람은 변수를 사용하지 않습니다. 대신 임시로 텍스트 배열을 사용합니다 : aa. 이유

void main() 
{
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

물론 작동하지 않습니다. 변수를 비교하지 않는 것입니다.
다음과 같은 변수를 생성하려는 경우 :

char * text = "a";
char * text2 = "a";

text와 비교할 수 text2있으며 사실 이어야 합니다.

어쩌면 당신은 사용하는 것을 잊지해야 {하고 }) =

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}

1
" and it should be true "-아니요 . 문자열 리터럴이 동일한 메모리 위치에 저장되는지 여부 는 지정되지 않습니다. 다른 답변을 읽으십시오.
Spikatrix
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.