바이트 + 바이트 = int… 왜? 수학의 결과 는 암시 적으로 정수로

이 C # 코드를 보면 :

byte x = 1;
byte y = 2;
byte z = x + y; // ERROR: Cannot implicitly convert type 'int' to 'byte'

byte(또는 short) 유형 에서 수행 된 모든 수학의 결과 는 암시 적으로 정수로 캐스트됩니다. 해결책은 명시 적으로 결과를 바이트로 다시 캐스팅하는 것입니다.

byte z = (byte)(x + y); // this works

내가 궁금한 것은 왜? 건축인가요? 철학적인가?

우리는 :

  • int+ int=int
  • long+ long=long
  • float+ float=float
  • double+ double=double

그래서 왜 안돼:

  • byte+ byte=byte
  • short+ short= short?

약간의 배경 : 나는 “작은 숫자”(즉, <8)에 대한 긴 계산 목록을 수행하고 중간 결과를 큰 배열로 저장합니다. (캐시 적중으로 인해 ) int 배열 대신 바이트 배열을 사용하는 것이 더 빠릅니다 . 그러나 광범위한 바이트 캐스트는 코드를 통해 확산되어 훨씬 더 읽을 수 없게 만듭니다.



답변

코드 스 니펫의 세 번째 줄 :

byte z = x + y;

실제로 의미

byte z = (int) x + (int) y;

따라서 바이트에는 + 연산이 없으며 바이트는 먼저 정수로 캐스트되고 두 정수를 더한 결과는 (32 비트) 정수입니다.


답변

“어떻게 발생 하는가”의 관점에서, 다른 사람들이 말했듯이 바이트, sbyte, short 또는 ushort로 산술하기 위해 C #으로 정의 된 연산자가 없기 때문입니다. 이 답변은 그 연산자가 정의되지 않았는 지에 관한 것입니다 .

나는 그것이 기본적으로 성능을 위해서라고 생각합니다. 프로세서는 32 비트로 매우 빠르게 산술 연산을 수행합니다. 결과에서 바이트로의 변환을 자동으로 수행 수는 있지만 실제로 해당 동작을 원하지 않는 경우 성능이 저하 될 있습니다.

나는 생각 이 주석 C #을 기준 중 하나에 언급되어있다. 보고있는 중 …

편집 : 짜증나게, 나는 이제 주석이 달린 ECMA C # 2 사양, 주석이 달린 MS C # 3 사양 및 주석 CLI 사양 을 살펴 보았으며, 내가 볼 수있는 한 아무도 언급 하지 않았습니다 . 난 확실히 내가 위의 이유를 본 적이 있지만 내가 어디 있는지 알고 있다면 난 불줄 해요. 사과, 참조 팬 🙁


답변

나는 이것을 어딘가에 본 적이 있다고 생각 했다. 에서 이 문서 올드 뉴 살아라 :

‘바이트’에 대한 작업이 ‘바이트’가 된 환상의 세계에 살았다 고 가정 해보십시오.

byte b = 32;
byte c = 240;
int i = b + c; // what is i?

이 환상의 세계에서 i의 가치는 16입니다! 왜? + 연산자에 대한 두 피연산자가 모두 바이트이므로 합계 “b + c”는 바이트로 계산되므로 정수 오버플로로 인해 16이됩니다. (앞서 언급했듯이 정수 오버플로는 새로운 보안 공격 벡터입니다.)

편집 : Raymond는 본질적으로 C와 C ++이 원래 취한 접근법을 방어하고 있습니다. 이 의견에서 그는 C #이 언어 이전 버전과의 호환성이라는 이유로 동일한 접근 방식을 취한다는 사실을 변호합니다.


답변

씨#

ECMA-334에 따르면 추가는 int + int, uint + uint, long + long 및 ulong + ulong (ECMA-334 14.7.4)에서만 법적으로 정의됩니다. 따라서, 이들은 14.4.2와 관련하여 고려해야 할 후보 작업입니다. 바이트에서 int, uint, long 및 ulong으로 암시 적 캐스트가 있기 때문에 모든 추가 함수 멤버는 14.4.2.1에서 적용 가능한 함수 멤버입니다. 14.4.2.3의 규칙에 따라 최상의 암시 적 캐스트를 찾아야합니다.

int (T1)에 캐스팅 (C1)을 캐스팅 (C2)을 uint (T2) 또는 ulong (T2)에 캐스팅하는 것보다 낫습니다.

  • T1이 int이고 T2가 uint이거나 ulong이면 C1이 더 나은 변환입니다.

int에서 long으로의 암시 적 캐스트가 있기 때문에 (C1)에서 int (T1)로 캐스트하는 것이 낫습니다 (C2).

  • T1에서 T2 로의 암시 적 변환이 존재하고 T2에서 T1 로의 암시 적 변환이 존재하지 않으면 C1이 더 나은 변환입니다.

따라서 int + int 함수가 사용되어 int를 반환합니다.

이것이 C # 사양에 매우 깊게 묻혀 있다고 말하는 매우 긴 방법입니다.

CLI

CLI는 6 가지 유형 (int32, native int, int64, F, O 및 &)에서만 작동합니다. (ECMA-335 파티션 3 섹션 1.5)

바이트 (int8)는 이러한 유형 중 하나가 아니며 추가하기 전에 자동으로 int32로 강제 변환됩니다. (ECMA-335 파티션 3 섹션 1.6)


답변

바이트를 추가하고 결과를 바이트로 다시 자르는 비 효율성을 나타내는 대답이 올바르지 않습니다. x86 프로세서에는 8 비트 수량의 정수 연산을 위해 특별히 설계된 명령어가 있습니다.

실제로 x86 / 64 프로세서의 경우 32 비트 또는 16 비트 작업을 수행하면 디코딩해야하는 피연산자 접두사 바이트로 인해 64 비트 또는 8 비트 작업보다 효율성이 떨어집니다. 32 비트 시스템에서 16 비트 작업을 수행하면 동일한 결과가 발생하지만 8 비트 작업을위한 전용 opcode가 여전히 있습니다.

많은 RISC 아키텍처에는 유사한 기본 단어 / 바이트 효율적인 명령어가 있습니다. 일반적으로 저장 및 변환에서 부호있는 값의 비트 길이를 갖지 않는 것.

다시 말해,이 결정은 하드웨어의 비 효율성 때문이 아니라 바이트 유형의 용도에 대한 인식을 기반으로해야합니다.


답변

바이트가 실제로 + 연산자에 과부하가 걸리지 않는 방법에 대해 Jon Skeet에서 무언가를 읽은 것을 기억합니다 (지금 찾을 수 없으며 계속 볼 것입니다). 실제로 샘플에서와 같이 2 바이트를 추가하면 각 바이트는 실제로 암시 적으로 int로 변환됩니다. 그 결과는 분명히 int입니다. 이제 이것이 이런 식으로 설계된 이유에 관해서는 Jon Skeet 자신이 게시 할 때까지 기다립니다.

편집 : 찾았어요! 이 주제에 대한 훌륭한 정보는 여기에 있습니다 .


답변

이것은 오버플로와 캐리 때문입니다.

두 개의 8 비트 숫자를 추가하면 9 비트로 오버플로 될 수 있습니다.

예:

  1111 1111
+ 0000 0001
-----------
1 0000 0000

나는 확실히 모르겠지만, 나는 가정 ints, longs그리고 doubles그들이 그대로 꽤 크기 때문에 더 많은 공간이 제공됩니다. 또한 4의 배수로, 내부 데이터 버스의 너비가 4 바이트 또는 32 비트 (현재 64 비트가 널리 보급되고 있음)이기 때문에 컴퓨터가보다 효율적으로 처리 할 수 ​​있습니다. 바이트와 ​​쇼트는 조금 더 비효율적이지만 공간을 절약 할 수 있습니다.