programing

왜 C자 리터럴은 chars가 아닌 int일까요?

goodcopy 2022. 8. 10. 00:10
반응형

왜 C자 리터럴은 chars가 아닌 int일까요?

C++에서는sizeof('a') == sizeof(char) == 1직감적으로 이해할 수 있습니다.'a'문자 그대로입니다.sizeof(char) == 1표준에 의해 정의된 대로.

단, C에서는sizeof('a') == sizeof(int)즉, C 문자의 리터럴은 실제로는 정수인 것 같습니다.왜 그런지 아는 사람?나는 이 C 기호에 대한 많은 언급을 찾을 수 있지만 왜 그것이 존재하는지 설명하지 못한다.

같은 문제에 관한 토론

"좀 더 구체적으로 말하면, 필수적인 프로모션입니다.K&R C에서는 문자값을 int로 승격하지 않고는 사실상 사용할 수 없었기 때문에 처음부터 문자값을 일정하게 int로 함으로써 그 단계를 생략했다.abcd와 같은 다중 문자 상수가 존재했고 지금도 존재하며 int에 들어갈 문자 수도 있습니다."

첫 번째 질문은 "왜?"입니다.

그 이유는 리터럴 문자의 정의가 기존 코드와의 하위 호환성을 유지하면서도 발전하고 변화했기 때문입니다.

초기 C의 어두운 시절에는 활자가 전혀 없었다.C에서 프로그래밍을 처음 배울 무렵에는 타입이 도입되었지만 함수에는 인수 타입을 호출자에게 알려주는 프로토타입이 없었습니다.대신 파라미터로 전달되는 모든 것이 int의 크기(이것은 모든 포인터를 포함한다)이거나 더블이 될 것이라고 표준화되었다.

즉, 함수를 쓸 때 이중화되지 않은 모든 파라미터는 선언 방법에 관계없이 스택에 ints로 저장되며 컴파일러는 이를 처리하기 위해 함수에 코드를 넣습니다.

이로 인해 다소 일관성이 없어졌기 때문에 K&R은 유명한 책을 쓸 때 문자 리터럴은 함수 파라미터가 아닌 어떤 표현에서도 int로 승격된다는 규칙을 적용했다.

ANSI 위원회가 C를 처음 표준화할 때, 그들은 이 규칙을 변경하여 문자 리터럴이 단순히 int가 되도록 했습니다. 왜냐하면 이것은 같은 것을 달성하는 더 간단한 방법처럼 보였기 때문입니다.

C++를 설계할 때는 모든 기능에 완전한 프로토타입을 장착해야 했습니다(C에서는 일반적으로 모범 사례로 인정되지만 여전히 이 시제품이 필요하지 않습니다).이 때문에 문자 리터럴을 문자 안에 저장할 수 있게 되었습니다.C++의 장점은 char 파라미터를 가진 함수와 int 파라미터를 가진 함수의 시그니처가 다르다는 것입니다.이 이점은 C에서는 해당되지 않습니다.

이것이 그들이 다른 이유입니다.진화...

왜 C의 문자 리터럴이 int 타입인지 구체적인 이유는 알 수 없습니다.하지만 C++에서는 그 길로 가지 않는 타당한 이유가 있다.다음 사항을 고려하십시오.

void print(int);
void print(char);

print('a');

인쇄하는 콜은 문자를 사용하는 두 번째 버전을 선택하는 것을 상정할 수 있습니다.문자 그대로 int가 되는 건 불가능할 거야C++ 리터럴에서는, 복수의 문자를 가지는 경우는, 그 값이 실장 정의되어 있습니다만, 여전히 타입 int 가 되어 있는 것에 주의해 주세요.그렇게,'ab'타입이 있다int,하는 동안에'a'타입이 있다char.

MacBook에서 gcc를 사용하여 다음을 시도합니다.

#include <stdio.h>
#define test(A) do{printf(#A":\t%i\n",sizeof(A));}while(0)
int main(void){
  test('a');
  test("a");
  test("");
  test(char);
  test(short);
  test(int);
  test(long);
  test((char)0x0);
  test((short)0x0);
  test((int)0x0);
  test((long)0x0);
  return 0;
};

실행 시 다음을 얻을 수 있습니다.

'a':    4
"a":    2
"":     1
char:   1
short:  2
int:    4
long:   4
(char)0x0:      1
(short)0x0:     2
(int)0x0:       4
(long)0x0:      4

즉, 의심하는 바와 같이 문자는 8비트이지만 문자 리터럴은 int입니다.

C가 작성되었을 때 PDP-11의 MACRO-11 어셈블리 언어에는 다음과 같은 기능이 있었습니다.

MOV #'A, R0      // 8-bit character encoding for 'A' into 16 bit register

이런 종류의 것은 어셈블리 언어에서 매우 일반적입니다. 하위 8비트는 문자 코드를 유지하고 다른 비트는 0으로 클리어합니다.PDP-11에는 다음과 같은 기능이 있습니다.

MOV #"AB, R0     // 16-bit character encoding for 'A' (low byte) and 'B'

이를 통해 16비트 레지스터의 하위 바이트와 상위 바이트에 두 문자를 쉽게 로드할 수 있습니다.그런 다음 텍스트 데이터나 화면 메모리를 업데이트하여 다른 곳에 쓸 수 있습니다.

그래서 글자 크기를 등록하는 것은 지극히 평범하고 바람직하다.단, 하드 코드화된 opcode의 일부가 아니라 다음과 같은 메인 메모리 내의 어딘가에서 A를 레지스터에 넣어야 한다고 가정해 봅시다.

address: value
20: 'X'
21: 'A'
22: 'A'
23: 'X'
24: 0
25: 'A'
26: 'A'
27: 0
28: 'A'

이 메인 메모리에서 A만 레지스터로 읽으려면 어떤 것을 읽으시겠습니까?

  • 일부 CPU는 16비트 레지스터에 대한 16비트 값 읽기만 직접 지원할 수 있습니다. 즉, 20비트 또는 22비트 읽기는 'X'의 비트를 지워야 하며 CPU의 엔디안성에 따라서는 하위 바이트로 전환해야 합니다.

  • CPU에 따라서는 메모리 정렬 읽기가 필요할 수 있습니다.즉, 최소 주소는 데이터 크기의 배수로 해야 합니다.주소 24와 25에서 읽을 수 있지만 27과 28은 읽을 수 없습니다.

따라서 레지스터에 'A'를 입력하기 위한 코드를 생성하는 컴파일러는 약간의 여분의 메모리를 낭비하고 값을 0 'A' 또는 'A' 0으로 인코딩하는 것을 선호할 수 있습니다.또한 엔디안성에 따라 값이 올바르게 정렬되어 있는지 확인합니다(홀수 메모리 주소가 아님).

C는 단순히 메모리 레지스터 크기를 점유하는 문자 상수를 생각하면서 CPU 중심의 동작을 반복하고 C를 "고레벨 어셈블러"로 평가한 것으로 추측입니다.

(http://www.dmv.net/dec/pdf/macro.pdf)의 6-25페이지 6.3.3을 참조하십시오).

나는 K&R을 읽고 EOF에 도달할 때까지 한 번에 한 문자를 읽는 코드 조각을 본 것을 기억한다.모든 문자는 파일/입력 스트림에 포함되는 유효한 문자이기 때문에 EOF는 char 값이 될 수 없습니다.코드는 읽기 문자를 int에 넣고 EOF를 테스트한 후 그렇지 않으면 char로 변환하는 것입니다.

이것이 당신의 질문에 정확히 답하지 못한다는 것을 알지만, 만약 EOF 리터럴이 맞다면 나머지 문자 리터럴의 사이즈는 어느 정도 의미가 있을 것입니다.

int r;
char buffer[1024], *p; // don't use in production - buffer overflow likely
p = buffer;

while ((r = getc(file)) != EOF)
{
  *(p++) = (char) r;
}

(C charliterals는 int타입)의 이유를 알 수 없지만 Strostrup은 이에 대해 (Design and Evolution 11.2.1 - Fine-Grane Resolution에서) 다음과 같이 말하고 있습니다.

C에서 다음과 같은 문자 리터럴의 유형입니다.'a'int의외로 주는 건'a'유형charC++에서는 호환성 문제는 발생하지 않습니다.병리학적 예시를 제외하고sizeof('a')C와 C++로 표현할 수 있는 모든 구성은 동일한 결과를 제공합니다.

그래서 대부분의 경우, 그것은 문제를 일으키지 않을 것입니다.

그 이유는 C와 그 이전 B가 원래 다양한 워드사이즈를 가진 다양한 DEC PDP 미니컴퓨터에서 개발되었기 때문입니다.이 모델에서는 8비트 ASCII를 지원하지만 레지스터에서만 연산할 수 있었습니다(단, PDP-11은 나중에 출시되었습니다).C의 초기 버전이 정의되어 있습니다.int기계의 원어민 크기이며, a보다 작은 값입니다.int까지 넓힐 필요가 있다int함수와 주고받거나 비트, 논리식 또는 산술식으로 사용할 수 있습니다.그것이 기본 하드웨어의 동작 방식이었기 때문입니다.

또한 이것이 정수 승격 규칙에서 여전히 다음과 같은 데이터 유형이 다음과 같은 이유이기도 합니다.int로 승진하다intC 구현은 또한 유사한 역사적 이유로 2의 완성이 아닌 1의 완성을 사용하는 것이 허용된다.8진수가 16진수에 비해 이스케이프되고 8진수 상수가 1등급 시민인 이유도 마찬가지로 초기 DEC 미니컴퓨터의 워드사이즈는 3바이트 청크로 분할되지만 4바이트 니블은 분할되지 않았기 때문입니다.

이것이 "통합 프로모션"이라고 불리는 올바른 행동입니다.다른 경우에서도 발생할 수 있습니다(내 기억이 맞다면 주로 이진 연산자).

편집: 만약을 위해 Expert C 프로그래밍 복사본을 확인했습니다. Deep Secrets, 그리고 char 리터럴은 int 타입으로 시작하지 않는다는 것을 확인했습니다.처음에는 char 타입이지만 에서 사용할 경우 int로 승격됩니다.이 책에서 인용한 내용은 다음과 같습니다.

문자 리터럴은 타입 int를 가지며 타입 char에서 승격 규칙을 따름으로써 도달합니다.이는 K&R 1(39페이지)에서 너무 간략하게 다루어져 있습니다.

표현식의 모든 문자는 int로 변환됩니다.식에 있는 모든 플로트는 이중으로 변환됩니다.function 인수는 식이기 때문에 type 변환은 인수가 함수에 전달될 때도 이루어집니다.특히 char와 short는 int가 되고 float는 이중으로 됩니다.

모르겠어요. 하지만 그렇게 하는 게 더 쉬웠을 거예요. 별로 중요하지 않았어요.타입이 호출되는 함수를 결정할 수 있게 된 것은 C++가 되어서였습니다.

나는 정말 이것을 몰랐다.프로토타입이 존재하기 전에는 int보다 좁은 것은 함수 인수로 사용할 때 int로 변환되었습니다.그것이 설명의 일부일 수도 있다.

이것은 언어 사양에 대한 접선일 뿐이지만, 하드웨어에서는 보통 32비트라는 레지스터 크기밖에 없습니다.따라서 실제로 (추가, 감산 또는 비교를 통해) char에서 동작할 때마다 레지스터에 로드될 때 int로 암묵적으로 변환됩니다.컴파일러는 예를 들어 2를 (서명되지 않은 문자) 254에 추가하면 256이 아닌 0으로 감겨버리도록 각 조작 후에 적절한 마스킹과 숫자 이동을 처리합니다.그러나 실리콘 내부에서는 다시 메모리에 저장할 때까지 int입니다.

이 언어는 8비트 리터럴 타입을 지정할 수 있기 때문에 학술적인 포인트입니다만, 이 경우 언어 사양은 CPU가 실제로 무엇을 하고 있는지를 보다 상세하게 반영하고 있습니다.

(x86 wongks는 예를 들어 짧은 폭의 레지스터를 한 번에 추가하는 네이티브 애드 조작이 있는 을 알 수 있지만, RISC 코어 내부에서는 두 단계로 변환됩니다.예를 들어 숫자를 추가한 후 Power의 애드/엑시 쌍과 같이 기호를 확장합니다.PC)

언급URL : https://stackoverflow.com/questions/433895/why-are-c-character-literals-ints-instead-of-chars

반응형