programing

64비트에서 32비트 부호 없는 곱셈이 정의되지 않은 동작을 유발합니까?

javamemo 2023. 6. 29. 19:40
반응형

64비트에서 32비트 부호 없는 곱셈이 정의되지 않은 동작을 유발합니까?

그래서 나는 이 코드를 가지고 있습니다:

uint32_t s1 = 0xFFFFFFFFU;
uint32_t s2 = 0xFFFFFFFFU;
uint32_t v;
...
v = s1 * s2; /* Only need the low 32 bits of the result */

다음 모든 사항에서 컴파일러는 다음 범위에 대한 선입견을 가질 수 없었습니다.s1또는s2위의 예에 해당하는 이니셜라이저.

만약 내가 이것을 32비트의 정수 크기를 가진 컴파일러에서 컴파일했다면 (예를 들어 x86을 컴파일할 때) 문제가 없습니다.컴파일러는 단순히 다음을 사용합니다.s1그리고.s2~하듯이uint32_t입력된 값(더 이상 승격할 수 없음), 곱셈은 단순히 주석이 말하는 대로 결과를 제공합니다(모듈로).UINT_MAX + 1이 경우 0x100000000)입니다.

하지만 64비트의 정수 크기를 가진 컴파일러(예: x86-64)에서 이것을 컴파일하면 C 표준에서 추론할 수 있는 정의되지 않은 동작이 있을 수 있습니다.정수 프로모션은 다음과 같습니다.uint32_t로 승격할 수 있습니다.int(64비트 서명), 곱셈은 2를 곱셈하려고 시도합니다.int예에 표시된 값이 있을 경우 정의되지 않은 동작인 정수 오버플로가 발생합니다.

제 말이 맞습니까? 그렇다면 어떻게 제정신으로 피하시겠습니까?

저는 유사하지만 C++을 다루는 이 질문을 발견했습니다: 부호 없는 정수를 모듈식으로 안전하게 곱하는 가장 좋은 C++ 방법은 무엇입니까?여기서 C에 해당하는 답변을 받고 싶습니다(C89 호환이 바람직함).하지만 64비트를 실행하는 빈약한 32비트 기계를 잠재적으로 허용 가능한 답을 곱하도록 만드는 것은 고려하지 않을 것입니다(일반적으로 이것이 우려되는 코드에서는 32비트 성능이 일반적으로 느린 기계이기 때문에 더 중요할 수 있습니다).

32비트 int 크기의 컴파일러로 컴파일할 때는 16비트 부호 없는 int에 동일한 문제가 적용될 수 있으며, 16비트 int 크기의 컴파일러로 컴파일할 때는 부호 없는 chars에 적용될 수 있습니다(후자는 8비트 CPU용 컴파일러에서 공통일 수 있습니다: C 표준은 정수가 16비트 이상이어야 합니다.따라서 적합한 컴파일러가 영향을 받을 수 있습니다).

부호가 없는 유형에서 곱셈을 발생시키는 가장 간단한 방법은 다음과 같습니다.uint32_t그리고 또한 적어도.unsigned int유형의 표현을 포함하는 것입니다.unsigned int.

v = 1U * s1 * s2;

은 이은변니다됩환것다를 변환합니다.1Uuint32_t또는s1그리고.s2unsigned int특정 플랫폼에 적합한 항목에 따라 달라집니다.

합니다. 여기서 @Deduplicator는 다음과 같습니다.uint32_t보다 .unsigned int할 수 으로 만들어 할 수 .

v = (uint32_t) (1U * s1 * S2);

하지만 제 생각에는 좀 덜 우아해 보입니다.

마찰점을 찾은 것을 축하합니다.

가능한 방법:

v = (uint32_t) (UINT_MAX<=0xffffffff
  ? s1 * s2
  : (unsigned)s1 * (unsigned)s2);

어쨌든, 몇 가지 유형 정의를 추가한 것 같습니다.<stdint.h>다음보다 작지 않도록 보장되는 유형의 경우int순서대로;-).

언급URL : https://stackoverflow.com/questions/27001604/32-bit-unsigned-multiply-on-64-bit-causing-undefined-behavior

반응형