2016-06-28 1 views
6

현재 비트 세트가 필요한 프로젝트에서 작업 중입니다. 비트 배열에 uint64_t 배열을 사용하고 있습니다. 내가 부문을 다시 작성하고 일부 영리 와 모듈로 할 수C - BitArray - uint64_t의 단일 비트 설정

uint64_t index = 42; 
bArr[index/64] |= (((uint64_t)1)<<(index%64)); 

:

내 현재의 문제는 내가 설정하거나 비트를 검사 할 때마다 나는이 같은 작업을 할 필요가있다 비트 시프트 작업뿐만 아니라, 나는 1의 캐스트에 대해 우려하고 있습니다. 그렇지 않으면 1이 32 비트 단위로 간주되므로이 캐스트가 필요합니다. 이 예에서 볼 수 있듯이 - 당신은 캐스트없이 잘못된 출력을 얻을 :

uint64_t bArr[4];       // 256 bits 
bArr[0] = bArr[1] = bArr[2] = bArr[3] = 0; // Set to 0 

uint64_t i = 255; 
bArr[i/64] = (bArr[i/64] | (((uint64_t)1)<<(i%64))); 

uint32_t i2; 
for (i2 = 0; i2 < 256; i2++) { 
    if ((bArr[i2/64] & (((uint64_t)1)<<(i2%64))) != 0) { 
    printf("bArray[%" PRIu32 "] = 1\n", i2); 
    } 
} 

나는 영리한 방법이 캐스트 주위를받을 수 있습니까? 나는 성능이 아마도 에서 캐스팅으로 인해 어려움을 겪고 있다고 생각했다. 읽기/쓰기 ...

+0

나누기를 다시 작성하지 않고 모듈을 "영리하게"만들지 않습니다. 컴파일러는 이미 그 최적화를 수행 할만큼 충분히 똑똑합니다. 또한 매직 번호를 피하려면'64' 대신'CHAR_BIT * sizeof bArr [0]'을 사용하는 것을 고려하십시오. – unwind

+0

@unwind 팁 주셔서 감사. 내 코드로 테스트 해 볼게. 그래도이 경우입니다. – Matthias

+0

속도를 찾고 있다면, 64 개의 서로 다른 ULL 상수 (모든 가능한 위치로 1 개 사전 시프트 됨)가있는'const uint64_t' 테이블을 제공하고 이에 인덱스를 지정하십시오. – tofro

답변

4

<< 연산자의 결과 유형은 (정수 프로모션 후) 왼쪽 피연산자의 유형 올바른 형식을 사용해야 그 이유는있다.

(uint64_t) 1 

또는

UINT64_C(1) /* you have to include <stdint.h> */ 

또는

1ULL 

이 (가정 마지막 하나 unsigned long long 매우 가능성이 시스템의 64 비트입니다되는 :

당신도 사용할 수 있습니다).

그러나 모두이 모든 표현식은 정수 상수 표현식이며 해당 값은 런타임에 컴파일 타임에 계산됩니다.

+0

컴파일 타임에 발생하고 성능에 영향을 미치지 않음을 알았습니다. (코드 만 uglifies) ... – Matthias

+1

세부 사항'unsigned long long은 64 비트 이상이므로'bArr [index/64] | = 1ULL << (인덱스 % 64);이 (가) 확실히 작동합니다. 'unsigned long long'은 64 비트가 필요 없다고 가정합니다. – chux

+0

@chux'unsigned long long'이 64 비트보다 클 때 깨질까요? 나는 정확히 무슨 일이 일어나고 있는지 모르겠다. 설명을 해보시겠습니까? 캐스트없이 어떻게됩니까? 나는 잘못된 출력을 보았고 폭을 가지고 무언가를해야한다고 가정했기 때문에 (따라서 성공적으로 캐스트를 시도했다.) 나는 왜 코드가 파손 되었는가를 알고 싶다. – Matthias

1

정확하게 이해하면 리터럴 1이 64 비트 이상 필요하다. 캐스트가없는 get this1 대신 1ull으로 작성하면됩니다. 이렇게하면 값이 1 인 unsigned long long 리터럴이 만들어집니다. 그러나 형식이 64 비트보다 길지는 않으므로 형식이 64 비트이기 때문에 캐스팅이 필요할 수 있습니다.

3

캐스트 자체는 성능에 영향을주지 않습니다. 컴파일러에게 표현식의 유형을 알려주는 컴파일 타임 구문입니다.

이 경우 모두 정수형 및 표현식이므로 성능에 영향을주지 않아야합니다. 1 유형 int입니다하지만 당신은 유형 uint64_t이 필요합니다

+0

아, 또 다시 :) 아마 당신이 기억할 수 있듯이 이것은 당신의 코드입니다 (단지'uint64_t' 만 가지고 있습니다). 또한'uint64_t','uint32_t','uint16_t' 또는'uint8_t' 배열에 어떤 크기가 가장 적합한 지 알고 있습니까? 내 마음에 L1/L2 캐시 크기를 가지고 있지만 그것에 대해 많이 알지는 못한다 ... – Matthias

+0

* 캐스트 [...]은 컴파일러에게 식의 유형을 알려주는 컴파일 타임 구조이다 * 그렇지 않다. 대부분의 경우 캐스팅은 컴파일 타임 구조라고 말할 수 있습니다. – ouah

3

C는 정수 상수를 int_leastN_t 유형으로 확장하는 매크로를 제공합니다.

INTN_C(value) 
UINTN_C(value) 

#include <stdint.h>. 
bArr[index/64] |= UINT64_C(1) << (index%64); 

일반적으로 에서는 캐스팅을 방지하는 것이 좋습니다. 예기치 않게 캐스팅하면 의 값이보다 좁아집니다.UINT64_C


장점 : uint_least_64_t/int_least_64_t 유형이 존재한다 (C99). int64_t/uint64_t은 선택 사항입니다.

+0

좋은 매크로, 팁 주셔서 감사합니다 :)이 경우 항상'uin64_t'에서 올바르게 작동하므로 캐스팅이 잘되어야합니다. – Matthias

+0

'(int64_t)'에 대한 캐스트보다'INT64_C'를 선택하면 어떤 이점이 있습니까? – a3f

+1

@ a3f 답변이 도움이되었습니다. N이> ='unsigned/int' width와'(u) intN_t'가 존재할 때, 확실히'INTN_C()'와'intN_t()'는 똑같이 동작합니다. – chux