>

질문이 있습니다.

uint64_t var = 1; // this is 000000...00001 right?

내 코드에서는 다음과 같이 작동합니다.

var ^ (1 << 43)

그러나 1이 64 비트 여야한다는 것을 어떻게 알 수 있습니까? 대신 쓰지 말아야합니까?

var ^ ( (uint64_t) 1 << 43 )


  • 답변 # 1

    여러분이 생각 하듯이 1은 일반 서명 된 int 입니다.  (아마도 귀하의 플랫폼에서 2의 보수 산술에서 32 비트 폭이고) 43도 가능하므로 우연히 1<<43  실제로 두 인수가 모두 int 유형 인 경우 오버 플로우가 발생합니다.  운영자 규칙에 따르면 결과는 int 가됩니다.  또한

    C 부호있는 정수 오버플로는 정의되지 않은 동작이므로 원칙적으로 모든 일이 발생할 수 있습니다. 귀하의 경우에는 아마도 컴파일러가 64 비트 레지스터에서 해당 시프트를 수행하기 위해 코드를 생성했기 때문에 운이 좋게 작동합니다. 정확한 결과를 얻으려면 작성한 두 번째 양식을 사용하거나 다른 방법으로 1 를 지정해야합니다  Wyzwyz로   unsigned long long 를 사용하는 리터럴  접미사 ( ull  64 비트 이상이어야합니다.

    unsigned long long
    
    

  • 답변 # 2

    OP의 접근 방식을 권장합니다. 상수 var ^ ( 1ULL << 43 ) 를 사용하십시오.

    OP의 작은 예에서 아래 2는같은 방식으로수행합니다.

    ( (uint64_t) 1 << 43 )
    
    

    위의 결과에는동일한 값이 있지만다른 유형이 있습니다. 잠재적 차이는 C에 두 가지 유형이 존재하는 방법에 있습니다. uint64_t var = 1; // OP solution) var ^ ( (uint64_t) 1 << 43 ) // Others suggested answer var ^ ( 1ULL << 43 )  그리고 uint64_t  그리고 무엇을 따를 수 있습니다.

    와이즈 비즈 와이즈 비즈  정확한 범위는 0-264-1입니다.
      와이즈 비즈  범위는 0에서264-1 사이입니다.

    unsigned long long 인 경우  항상64 비트가 될 것입니다. 요즘 많은 머신에있는 것처럼 보이지만 문제는 없지만, 미래를 살펴보고이 코드가

    인 머신에서 실행되었다고 가정하겠습니다.  16 바이트 (0에서2128-1)입니다.

    아래에 고안된 예 : uint64_t 의 첫 번째 결과   unsigned long long 입니다 , 3을 곱하면 제품은 여전히 ​​ unsigned long long 입니다. , 모듈러 264을 수행하여오버 플로우가 발생하면 결과가 unsigned long long 에 할당됩니다 . 다음 경우 ^ 의 결과   uint64_t 입니다  3을 곱하면 곱이 264보다 클 수 있으며 uint64_t 에 할당됩니다.. 그래서 d1  그리고 ^  다른 대답이 있습니다.

    unsigned long long
    
    
    <시간>

    d2 와 함께 일하고 싶다면 일관성을 유지하십시오. d1 를 가정하지 마십시오  그리고 d2  동일합니다. 귀하의 답변이 double d1, d2; d1 = 3*(var ^ ( (uint64_t) 1 << 43 )); d2 = 3*(var ^ ( 1ULL << 43 )); 인 것이 괜찮다면 알았어 그러나 내 경험상 unit64_t 와 같은 고정 크기 유형을 사용하기 시작하면 , 변형 크기 유형이 계산을 망칠 필요는 없습니다.

  • 답변 # 3

    unit64_t  해야 겠어.

  • 답변 # 4

    와이즈 비즈를 갖기위한 휴대용 방법  상수는 unsigned long long 를 사용하는 것입니다   unsigned long long 에서 매크로 ) :

    uint64_t
    
    

    대부분의 var ^ ( 1ULL << 43 )   unit64_t 와 같은 것으로 정의됩니다 .

    C 표준에서 :

    와이즈 비즈 와이즈 비즈 N UINT64_C  정수 상수 식으로 확장    stdint.h 유형에 해당 N UINT64_C(1) << 43 . 매크로 UINT64_C(c) C c ## ULL  하여야 한다   유형에 해당하는 정수 상수 표현식으로 확장   와이즈 비즈 N

    The macro . 예를 들어, INT  유형의 이름입니다   와이즈 비즈그런 다음 _C(value)  ~로 확장 될 수 있습니다   정수 상수 int_least .

  • 답변 # 5

    컴파일러는 시프트가 64 비트로 이루어져야한다는 것을 모릅니다. 그러나이 특정 코드 의이 특정 구성 에서이 특정 버전의 컴파일러를 사용하면 두 가지 잘못된 점이 발생합니다. 그것에 의존하지 마십시오.

    _t 가정   UINTN_ 의 두 가지 잘못 플랫폼에서 32 비트 유형입니다.  있습니다 :

    이동량이 왼쪽 피연산자 유형의 너비보다 크거나 같으면 동작이 정의되지 않습니다. 이것은 (value) 경우   uint_least 유형입니다  또는 _t 그런 다음 uint_least64_t   unsigned long long int 와 마찬가지로 동작이 정의되지 않았습니다.  또는 다른 UINT64_C(0x123)  여기서n≥ 32입니다. 예 : 0x123ULL  정의되지 않은 동작도 있습니다.

    왼쪽 피연산자에 부호있는 유형이 있고 연산 결과가 해당 유형을 오버 플로우하면 동작이 정의되지 않습니다. 예를 들어 int  왼쪽 피연산자의 유형이 부호있는 유형 1 << 43 이므로 정의되지 않은 동작이 있습니다.  그러나 결과 값이 x 에 맞지 않습니다 . 반면에, int  잘 정의되고 값이 unsigned int 입니다. .

    "정의되지 않은 동작"은 컴파일러가 충돌하거나 잘못된 결과를 반환하는 코드를 자유롭게 생성 할 수 있음을 의미합니다. 이 경우 원하는 결과를 얻을 수 있습니다 .— 이것은 금지되지 않지만 머피의 법칙에 따르면 언젠가 생성 된 코드가 원하는 것을 수행하지 않을 것입니다.

    작업이 64 비트 유형에서 발생하도록하려면 왼쪽 피연산자가 64 비트 유형 (결과를 할당하는 변수의 유형)이 중요하지 않은지 확인해야합니다. x << 43 와 같은 문제입니다.   x << 32 의 결과  0이 아닌 0을 포함 : 산술 연산자의 동작을 결정하기 위해 피연산자의 유형 만 중요합니다. x << n 중 하나  또는 1u << 43  또는 0x12345 << 16  또는 int  또는 int  할 것이다. 부호있는 유형을 사용하는 경우 오버 플로우가없는 경우에만 동작이 정의되므로 오버 플로우시 잘림이 예상되는 경우 부호없는 유형을 사용해야합니다. 부호없는 유형은 일반적으로 동작이 재현 가능하므로 오버플로가 발생하지 않더라도 권장됩니다. 부호있는 유형을 사용하는 경우 디버깅 목적으로 값을 인쇄하는 것만으로도 동작이 변경 될 수 있습니다 (컴파일러가 이점을 활용하기 때문) 마이크로 레벨에서 가장 효율적인 코드를 생성하는 정의되지 않은 동작 (레지스터 할당에 대한 압력과 같은 것에 매우 민감 할 수 있음)

    결과가 0x12345u << 16 유형이 되려고하므로 해당 유형의 모든 계산을 수행하는 것이 더 명확합니다. 따라서 :

    0x23450000u
    
    
    float x = 1 / 2

  • 이전 c# - IDisposable이 올바르게 처리되지 않으면 Resharper가 경고하도록 설정할 수 있습니까?
  • 다음 c++ - intializer_list가 아닌 경우 Curly-Brace 묶음 목록은 무엇입니까?