programing

C에서 비트필드를 사용하는 경우

goodcopy 2022. 8. 1. 21:45
반응형

C에서 비트필드를 사용하는 경우

'비트필드를 사용해야 하는 이유'라는 질문에서 구글에서 검색한 결과 플래그에 비트필드가 사용되고 있음을 알 수 있었습니다.이제 궁금해지는데

  1. 실제로 비트필드를 사용하는 유일한 방법입니까?
  2. 공간을 절약하려면 비트 필드를 사용해야 합니까?

책에서 비트 필드를 정의하는 방법:

struct {
    unsigned int is_keyword : 1; 
    unsigned int is_extern :  1; 
    unsigned int is_static : 1;
} flags;
  1. int를 사용하는 이유는 무엇입니까?
  2. 얼마나 많은 공간을 차지합니까?

왜 요.int 않다.shortint.

  1. 제가 알기로는 메모리에는 1비트만 사용되고 부호 없는 전체 int 값은 사용되지 않습니다.맞습니까?

그런데 실제로 비트필드를 사용할 수 있는 방법은 플래그뿐입니다.

아니요, 비트필드를 사용하는 방법은 플래그뿐만이 아닙니다.플래그가 더 일반적이긴 하지만 이 플래그를 사용하여 1비트보다 큰 값을 저장할 수도 있습니다.예:

typedef enum {
    NORTH = 0,
    EAST = 1,
    SOUTH = 2,
    WEST = 3
} directionValues;

struct {
    unsigned int alice_dir : 2;
    unsigned int bob_dir : 2;
} directions;

공간을 절약하려면 비트 필드를 사용해야 합니까?

비트 필드는 공간을 절약합니다.또한 바이트 정렬되지 않은 값을 더 쉽게 설정할 수 있습니다. 및 조작을 사용하는 것이 , 「」의 할 수 .struct가독성이 향상됩니다.하면, 「」라고 쓸 수 .

directions.alice_dir = WEST;
directions.bob_dir = SOUTH;

, 1개의 개의 int비트필드가 ( 다른 은 다음과 같이

#define ALICE_OFFSET 0
#define BOB_OFFSET 2
directions &= ~(3<<ALICE_OFFSET); // clear Alice's bits
directions |= WEST<<ALICE_OFFSET; // set Alice's bits to WEST
directions &= ~(3<<BOB_OFFSET);   // clear Bob's bits
directions |= SOUTH<<BOB_OFFSET;  // set Bob's bits to SOUTH

비트필드의 가독성 향상은 여러 바이트를 저장하는 것보다 훨씬 중요합니다.

int를 사용하는 이유는 무엇입니까?얼마나 많은 공간을 차지합니까?

【 の の 【 】int사용중입니다.사용하고 있습니다int왜냐하면 많은 경우, 그것은 별로 중요하지 않기 때문입니다.1개의 값에 대해 1 또는 2가 아닌 4바이트를 사용하는 경우 사용자는 알아차리지 못할 수 있습니다.하기 때문에 적게 타입(「」)을 할 수 .char,short,uint8_t 참조)

제가 알기로는 메모리에는 1비트만 사용되고 부호 없는 전체 int 값은 사용되지 않습니다.맞습니까?

아,, 그그않않않않. ★★unsigned int8시 정각

적절한 리소스는 C의 비트필드입니다.

기본적인 이유는 사용하는 사이즈를 줄이기 위해서입니다.예를 들어, 다음과 같이 쓸 수 있습니다.

struct {
    unsigned int is_keyword; 
    unsigned int is_extern; 
    unsigned int is_static;
} flags;

적어도 사용하다3 * sizeof(unsigned int)또는 3개의 작은 플래그를 나타내기 위해 12바이트가 필요합니다.

다음과 같이 적습니다.

struct {
    unsigned int is_keyword : 1; 
    unsigned int is_extern : 1; 
    unsigned int is_static : 1;
} flags;

1과 하게 됩니다.unsigned int즉 입니다.32개의 1비트필드를 구조체에 할당하면 더 많은 공간이 필요합니다.

이것은 기존의 홈브루 비트필드와 동등합니다.

#define IS_KEYWORD 0x01
#define IS_EXTERN  0x02
#define IS_STATIC  0x04
unsigned int flags;

단, 비트필드 구문은 보다 명확합니다.비교해 주세요.

if (flags.is_keyword)

대상:

if (flags & IS_KEYWORD)

확실히 에러 발생률이 낮아집니다.

비트필드가 일반적인 또 다른 장소는 하드웨어 레지스터입니다.각 비트가 특정 의미를 갖는 32비트 레지스터가 있는 경우 비트필드로 우아하게 설명할 수 있습니다.

이러한 비트필드는 본질적으로 플랫폼 고유의 것입니다.이 경우 휴대성은 문제가 되지 않습니다.

Brian Hook(ISBN 1-59327-056-9, 독일어판 ISBN 3-937514-19-8)의 저서 "Write Portable Code"에 따르면 "When to use bit-fields in C?" (C에서 비트필드를 사용할 때)에 대한 답변과 개인적인 경험을 제공합니다.

C언어의 비트필드 숙어를 사용하지 말고 직접 사용하세요.

많은 구현 세부 사항은 컴파일러에 따라 다르며, 특히 조합과 조합하여 컴파일러 및 엔디안이 다를 경우 보장되지 않습니다.다른 아키텍처 및/또는 다른 컴파일러용으로 컴파일될 가능성이 매우 낮다면 코드를 사용하지 마십시오.

독점 컴파일러를 탑재한 리틀 엔디언 마이크로 컨트롤러에서 GCC를 탑재한 다른 빅 엔디언 마이크로 컨트롤러로 코드를 이식할 때 이 케이스는 재미없었습니다. :-/

이후 플래그(host byte order;-)를 사용하는 방법은 다음과 같습니다.

# define SOME_FLAG        (1 << 0)
# define SOME_OTHER_FLAG  (1 << 1)
# define AND_ANOTHER_FLAG (1 << 2)

/* test flag */
if ( someint & SOME_FLAG ) {
    /* do this */
}

/* set flag */
someint |= SOME_FLAG;

/* clear flag */
someint &= ~SOME_FLAG;

그러면 int 타입과 비트필드 구조를 가진 결합이 필요하지 않습니다.임베디드 코드를 많이 읽으면 테스트, 세트, 클리어 패턴이 일반화되어 코드에서 쉽게 찾을 수 있습니다.

플래그 구조에는 비트필드(배타적이지는 않지만)를 주로 사용합니다(바이트 또는 워드(또는 종종 2스테이트)의 작은 정보(종종 관련된 정보)를 사용합니다.

이러한 시나리오에서는 비트필드가 올바르게 모델화되어 있기 때문에 비트필드가 사용됩니다.이러한 필드는 실제로는 8비트(16비트, 24비트, 32비트)의 숫자가 아니라 8비트(16비트, 24비트, 32비트)의 관련 정보를 모은 것입니다.

비트 필드를 사용하여 해결되는 문제는 정보를 엄격하게 "패킹"하면 측정 가능한 이점이 있거나 정보를 "패킹 해제"하면 불이익이 발생하지 않는 문제입니다.예를 들어, 1바이트에서 8핀까지 노출하고 각 핀의 비트가 보드에 이미 인쇄되어 있는 자체 버스를 통과하여 정확히 정해진 위치에 도달하는 경우 비트 필드가 이상적입니다.데이터를 「패킹」할 때의 이점은, 한 번에 송신할 수 있는 것(버스의 빈도가 한정되어 있고, 동작의 빈도에 의존하는 경우에 도움이 된다)과 데이터의 「패킹 해제」의 단점은 존재하지 않는 것(또는 존재하지만 가치가 있는 것)입니다.

한편, 일반적인 프로그램 흐름 제어와 같은 경우에는 컴퓨터 아키텍처가 일반적으로 작동하는 방식이기 때문에 부울란에는 비트 필드를 사용하지 않습니다.대부분의 일반적인 CPU는 메모리에서1비트를 가져오는 것을 좋아하지 않습니다.바이트나 정수를 가져오는 것을 좋아합니다.또한 비트 처리도 좋아하지 않습니다. 명령어는 정수, 워드, 메모리 주소 등과 같은 더 큰 것으로 동작합니다.

따라서, 비트로 조작하려고 할 때는, 비트 마스킹을 실행하는 추가 조작을 기입해, 실제로 조작하고 싶은 정보를 제외한 모든 것의 구조를 삭제하는 것은, 사용자 또는 컴파일러(어느 언어로 쓰는가에 따라 다릅니다)에게 달려 있습니다.정보를 "패킹"해도 아무런 이점이 없는 경우(대부분은 없습니다), Boolean에 비트필드를 사용하면 코드에 오버헤드와 노이즈만 발생합니다.

메모리 공간을 절약하기 위해 비트필드를 사용할 수 있습니다(단, 비트필드를 사용하는 경우는 거의 없습니다.임베디드 시스템에서 프로그래밍하는 등 메모리 제약이 있는 경우에 사용합니다.

단, 비트 필드의 주소는 지정할 수 없으므로 주소 연산자와 주소 연산자를 함께 사용할 수 없기 때문에 이것은 매우 필요한 경우에만 사용해야 합니다.

base64 또는 정렬되지 않은 데이터 구조를 변환하기 위한 청크를 구현하는 것이 좋습니다.

struct {
    unsigned int e1:6;
    unsigned int e2:6;
    unsigned int e3:6;
    unsigned int e4:6;
} base64enc; //I don't know if declaring a 4-byte array will have the same effect.

struct {
    unsigned char d1;
    unsigned char d2;
    unsigned char d3;
} base64dec;

union base64chunk {
    struct base64enc enc;
    struct base64dec dec;
};

base64chunk b64c;
//you can assign 3 characters to b64c.enc, and get 4 0-63 codes from b64dec instantly.

늘 base64가 을 고려해야 합니다.l 해서l% 3 0 0 ) 。그러나 정렬되지 않은 데이터 구조에 액세스하는 샘플로 작동합니다.

또 다른 예는 다음과 같습니다. 기능을 사용하여 TCP 패킷헤더를 컴포넌트(또는 설명하는 기타 네트워크 프로토콜 패킷헤더)로 분할하는 것으로, 보다 고도의 최종 유저의 예라고 할 수 있습니다.일반적으로: 이것은 PC 내부, SO, 드라이버, 인코딩 시스템에 유용합니다.

다른의 예를 들어 다음과 같습니다.float★★★★★★ 。

struct _FP32 {
    unsigned int sign:1;
    unsigned int exponent:8;
    unsigned int mantissa:23;
}

union FP32_t {
    _FP32 parts;
    float number;
}

(면책자:이것이 적용되는 파일 이름/유형 이름은 알 수 없지만 C에서는 헤더로 선언됩니다.맨티사는 52비트, -in a 32bit target-ints는 32비트가 필요하기 때문에 64비트 플래트에 대해 어떻게 이 작업을 수행할 수 있는지 알 수 없습니다).

결론:개념과 이러한 예에서 알 수 있듯이, 이것은 거의 사용되지 않는 기능입니다.대부분은 내부용이며 일상적인 소프트웨어용이 아니기 때문입니다.

메모리 공간을 활용하기 위해 비트 필드를 사용할 수 있습니다.

내가 아는 한 현실세계 프로그래밍에서는 우리가 필요로 하는 경우 정수로 선언하고 비트 필드를 만드는 대신 부란을 사용할 수 있다.

자주 사용하는 값이라면 공간을 절약할 수 있을 뿐만 아니라 캐시를 오염시킬 필요가 없기 때문에 성능도 얻을 수 있습니다.그러나 서로 다른 비트에 대한 동시 읽기 및 쓰기가 데이터 경합을 일으키고 완전히 분리된 비트로 업데이트하면 새 값이 이전 값으로 덮어쓸 수 있으므로 비트 필드를 사용할 때 캐싱도 위험합니다.

비트필드를 사용해야 하는 이유는 무엇입니까?

바이트 미만으로 저장할 수 있는 일부 데이터를 저장하려는 경우 비트 필드를 사용하여 이러한 데이터를 구조에서 결합할 수 있습니다.임베디드 워드에서 레지스터의 32비트 월드가 워드마다 다른 의미를 가질 경우 비트 파일도 사용하여 읽기 쉽게 만들 수 있습니다.

플래그에는 비트 필드가 사용되고 있는 것을 알았습니다.그런데 실제로 비트필드를 사용하는 방법은 이 방법뿐인가요?

아니, 이게 유일한 방법은 아니야.다른 방법으로도 사용할 수 있습니다.

공간을 절약하려면 비트 필드를 사용해야 합니까?

네.

제가 알기로는 메모리에는 1비트만 사용되고 부호 없는 전체 int 값은 사용되지 않습니다.맞습니까?

아니요. 메모리는 여러 바이트에서만 사용할 수 있습니다.

이를 사용하여 래핑되는 부호 없는 유형의 수를 확장할 수 있습니다.보통 8,16,32,64의 파워밖에 없지만 비트필드를 사용하여 모든 파워를 가질 수 있습니다.

struct a
{
    unsigned int b : 3 ;
} ;

struct a w = { 0 } ;

while( 1 )
{
    printf("%u\n" , w.b++ ) ;
    getchar() ;
}

비트필드는 훨씬 더 콤팩트하며 이것이 장점입니다.

하지만 꽉 찬 구조물은 일반 구조물보다 느리다는 것을 잊지 마세요.프로그래머가 각 필드에 사용할 비트 수를 정의해야 하기 때문에 구성하기도 더 어렵습니다.이것은 단점입니다.

질문의 일부에 대답하기 위해 다른 누구도 대답하지 않았습니다.

쇼트 이외의 입력

short 등이 아닌 int를 사용하는 이유는 대부분의 경우 int를 사용해도 공간이 절약되지 않기 때문입니다.

최신 컴퓨터는 32비트 또는 64비트 아키텍처를 가지고 있으며 쇼트 등 작은 스토리지 유형을 사용하더라도 32비트 또는 64비트가 필요합니다.

작은 타입은, 메모리 절약에 도움이 됩니다(예를 들면, 쇼트 어레이는 쇼트 어레이로 압축할 수 있기 때문에, 쇼트 어레이는 int 어레이보다 메모리를 적게 사용할 수 있습니다).대부분의 경우 비트필드를 사용할 때는 그렇지 않습니다.

기타 용도

비트필드는 플래그에 가장 일반적으로 사용되지만 다른 용도로도 사용됩니다.예를 들어 많은 체스 알고리즘에서 사용되는 체스 보드를 나타내는 한 가지 방법은 64비트 정수를 사용하여 보드(8*8픽셀)를 나타내고 그 정수로 플래그를 설정하여 모든 흰색 폰의 위치를 지정하는 것입니다.다른 정수는 모든 검은 폰 등을 나타냅니다.

int를 사용하는 이유는 무엇입니까?얼마나 많은 공간을 차지합니까?

이 질문에 대한 답변 중 하나는 C 규격이 int에 대한 지원을 보장한다는 것입니다.구체적으로는:

비트필드에는 _Bool, signed int, unsigned int 또는 기타 구현 정의 유형의 적격 또는 부적격 버전이 있어야 합니다.

컴파일러는 일반적으로 추가 비트필드 유형을 허용하지만 필수는 아닙니다.휴대성을 정말로 중시하는 경우는, int가 최적입니다.

프로젝트에서는, 이것을 사용하고, 지정된 메모리 주소로부터 페이지 테이블 엔트리 및 페이지 디렉토리 엔트리를 추출했습니다.

union VADDRESS {
    struct {
        ULONG64 BlockOffset : 16;
        ULONG64 PteIndex : 14;
        ULONG64 PdeIndex : 14;
        ULONG64 ReservedMBZ : (64 - (16 + 14 + 14));
    };

    ULONG64 AsULONG64;
};

이제 가 있다고 가정해 보겠습니다.union VADDRESS tempAddress; tempAddress.AsULONG64 = 0x1234567887654321;

이제 다음 주소에서 PTE 및 PDE에 액세스할 수 있습니다.
cout < temp Address >PteIndex;

오늘날 마이크로컨트롤러(MCU)에는 프로세서와 함께 칩에 I/O 포트, ADC, DAC 등의 주변기기가 탑재되어 있습니다.MCU가 필요한 주변기기를 사용할 수 있게 되기 전에 마이크로프로세서의 버퍼링된 주소와 데이터 버스에 접속하여 하드웨어에 액세스했습니다.포인터는 디바이스의 메모리 주소로 설정되며, 디바이스가 주소를 r/w 및 칩 선택과 함께 인식하면 액세스 됩니다.디바이스상의 개별 또는 소규모 비트그룹에 액세스 하고 싶은 경우가 많습니다.

언급URL : https://stackoverflow.com/questions/24933242/when-to-use-bit-fields-in-c

반응형