문제
런타임 시 결정되는 많은 양의 불리언 정보를 저장하려고 합니다.가장 좋은 방법이 무엇인지 궁금합니다.
현재 다음을 사용하여 메모리를 할당하려고 시도했습니다.
pStatus = malloc((<number of data points>/8) + 1);
이것이 나에게 작업하기에 충분한 비트를 제공할 것이라고 생각합니다.그런 다음 배열 표기법의 포인터를 사용하여 각 부울 값을 참조할 수 있습니다.
pStatus[element]
불행히도 이것은 잘 작동하지 않는 것 같습니다.첫째, 메모리를 정수 값으로 초기화하는 데 어려움이 있습니다. 0
.다음을 사용하여 이 작업을 수행할 수 있습니까? memset()
?그래도 액세스하려고 할 때 충돌이 발생하는 이유에는 이것이 영향을 미치지 않는다고 생각합니다. pStatus[element]
.
나는 또한 이 접근법이 사용하기에 가장 좋은 접근법이라고 완전히 확신하지 못합니다.내가 정말로 원하는 것은 본질적으로 부울 값의 상태를 반영하는 거대한 비트마스크입니다.내가 뭔가를 놓친 걸까요?
해결책
pStatus = malloc((<number of data points>/8) + 1);
이것은 비트에 충분한 바이트를 할당합니다. 하지만,
pStatus[element]
이것은 요소에 액세스합니다 바이트, 비트가 아닙니다. 따라서 요소가 총 비트 수의 8 분의 1 이상이면 배분 된 배열의 끝에 액세스 할 수 있습니다.
몇 가지 도우미 기능을 정의합니다
int get_bit(int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
return ((pStatus[byte_index] & bit_mask) != 0);
}
void set_bit (int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
pStatus[byte_index] |= bit_mask);
}
void clear_bit (int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
pStatus[byte_index] &= ~bit_mask;
}
(명확성을 위해 외식하는 요소 범위에 대한 오류 확인.이 매크로도 만들 수도 있습니다)
다른 팁
... 이것이 나에게 충분한 비트를 줄 것이라고 생각합니다. 그런 다음 배열 표기법의 포인터를 사용하여 각 부울 값을 참조 할 수 있습니다.
pStatus[element]
요소가 해결 중입니다 바이트, 비트가 아닙니다. 당신은 다음과 같은 것을 원합니다 :
pStatus[element/8] & (1 << (element % 8))
작은 포인트 : N 비트를 저장하기에 충분한 메모리를 얻으려면 (N/8) + 1 바이트는 부정확합니다 (너무 많을 수 있음).
(n+7)/8은 항상 최소 수입니다.
글쎄, 가장 간단한 대답은 Malloc 대신 Calloc을 사용하는 것입니다.
그것은 메모리를 0으로 할당하는 메모리를 초기화하도록 정의되며 종종 페이지 매핑 트릭을 사용하여 수행 할 수 있습니다.
메모리 초기화 문제를 처리합니다. 여기서 다른 12 개의 게시물은 인덱싱 문제와 때때로 여분의 바이트 (오 공포!)를 할당한다는 사실을 적절히 해결하는 것 같습니다.
Pstatus [요소]는 해당 주소에서 전체 바이트를 제공합니다.
특정 요소를 설정하려면 다음과 같은 작업을 수행합니다.
pStatus[element >> 3] |= 1 << (element & 7);
요소를 재설정하려면 :
pStatus[element >> 3] &= ~1 << (element & 7);
그리고 요소를 테스트하려면 :
if (pStatus[element >> 3] & (1 << (element & 7)) != 0)
초기 할당이 있어야합니다
pstatus = malloc((<number of data points> + 7) / 8)
당신이 가진 것은 효과가 있지만 때때로 바이트를 낭비합니다.
여기서 C의 모든 응답은 바이트가 8비트라고 가정하는 것 같습니다.이는 C에서는 반드시 그렇지는 않습니다(물론 대부분의 주류 하드웨어에서는 해당되지만). 따라서 코드에서 이러한 가정을 하는 것은 다소 나쁜 형식입니다.
아키텍처 중립적인 코드를 작성하는 올바른 방법은 다음과 같습니다.
#include <limits.h>
그런 다음 CHAR_BIT
매크로가 필요할 때마다 "비트 수 char
".
자신을 더 행복하게 만들고 해당 유형에서 작동 할 유형과 기능을 정의하십시오. 이렇게하면 비트 액세스가 너무 느리다는 것을 알면 부울 당 메모리 단위를 바이트/워드/롱으로 변경하거나 메모리가 실제로 문제 인 경우 스파 스/동적 데이터 구조를 채택 할 수 있습니다 (예 : 세트가 대부분 세트 인 경우. , 당신은 단지 1의 좌표로 목록을 유지할 수 있습니다.
비트 벡터의 구현 변경에 완전히 면역되도록 코드를 작성할 수 있습니다.
pstatus [요소]는 비트를 다루지 않습니다. 정확한 바이트는 pstatus의 유형에 따라 달라집니다 - 나는 char* 또는 동등한 것으로 가정하므로 pstatus [요소]는 요소 바이트를 얻습니다.
0으로 설정할 수 있습니다.
pStatus = malloc((<number of data points>/8) + 1);
그 부분은 괜찮습니다.
pStatus[element]
여기에 문제가있는 곳이 있습니다. 비트를 해결하려면 주소 바이트입니다.
pStatus[element / 8 ]
배열에서 올바른 바이트를 얻을 수 있습니다.
할당해야합니다 c = malloc((N+7)/8)
바이트, 당신은 n을 설정할 수 있습니다
c[n/8]=((c[n/8] & ~(0x80 >> (n%8))) | (0x80>>(n%8)));
명확하게
c[n/8] &= ~(0x80 >> (n%8));
그리고 테스트
if(c[n/8] & (0x80 >> (n%8))) blah();
랩퍼를 쓰지 않아도 C ++의 STL에서 Bit_set 또는 Bit_vector를 사용할 수도 있습니다. (특히 후자)는 정확히 필요한 것, 이미 코딩, 테스트 및 포장 된 것 같습니다 (및 많은 종과 휘파람 ).
C 응용 프로그램에서 C ++ 코드를 사용하는 간단한 방법이 부족한 것은 정말 부끄러운 일입니다 (아니요, 래퍼를 만드는 것은 나에게 간단하지 않으며 장기적으로 더 많은 작업을 의미합니다).
무엇이 잘못되었는지 std::vector<bool>
?
여기에 하나의 대답만이 char_bit을 언급한다는 것이 놀랍습니다. 바이트는 종종 8 비트이지만 항상 그런 것은 아닙니다.
할당 코드가 정확합니다 set_bit()
그리고 get_bit()
주어진 기능 이 답변 부울에 접근합니다.
Eaanon01 솔루션 대신 몇 비트로 제한되어 있다면 B 비트 필드의 C 내장 시설을 사용하십시오 (사용할 수있는 경우는 거의 없지만 이것은 하나 일 것입니다).
이 비트 뱅킹 물건에 대해 추천 할 수 있습니다 : Herny Warrens "Hacker Delight"
부울은 C에서 별도의 값이 "절대" 없습니다.그래서 구조체가 당신을 움직이게 할 수도 있습니다.
mem 영역을 초기화하지 않기 때문에 개별적으로 초기화해야 하는 것은 사실입니다.
다음은 공용 구조체 및 열거형을 사용하여 이를 수행할 수 있는 방법에 대한 간단한 예입니다.
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long int DWORD;
typedef unsigned long long int DDWORD;
enum STATUS
{
status0 = 0x01,
status1 = 0x02,
status2 = 0x04,
status3 = 0x08,
status4 = 0x10,
status5 = 0x20,
status6 = 0x40,
status7 = 0x80,
status_group = status0 + status1 +status4
};
#define GET_STATUS( S ) ( ((status.DDBuf&(DDWORD)S)==(DDWORD)S) ? 1 : 0 )
#define SET_STATUS( S ) ( (status.DDBuf|= (DDWORD)S) )
#define CLR_STATUS( S ) ( (status.DDBuf&= ~(DDWORD)S) )
static union {
BYTE BBuf[8];
WORD WWBuf[4];
DWORD DWBuf[2];
DDWORD DDBuf;
}status;
int main(void)
{
// Reset status bits
status.BBuf[0] = 0;
printf( "%d \n", GET_STATUS( status0 ) );
SET_STATUS( status0 );
printf( "%d \n", GET_STATUS( status0 ) );
CLR_STATUS(status0);
printf( "%d \n", GET_STATUS( status0 ) );
SET_STATUS( status_group );
printf( "%d \n", GET_STATUS( status0 ) );
system( "pause" );
return 0;
}
도움이 되었기를 바랍니다.이 예제는 최대 64개의 상태 부울까지 처리할 수 있으며 쉽게 확장할 수 있습니다.
이 예는 Char = 8비트 int = 16비트 long int = 32비트 및 long long int = 64비트를 기반으로 합니다.
이제 상태 그룹에 대한 지원도 추가되었습니다.