2010-01-24 7 views
13

나는 이런 식으로 바이트의 일부 비트를 포장해야합니다C/C++ 비트 필드 대 비트 단위 연산자를 사용하면 더 빠르고, 더 좋고, 더 이식성이 뛰어 납니까?

struct 
{ 
    char bit0: 1; 
    char bit1: 1; 
} a; 

if(a.bit1) /* etc */ 

나 : 소스 코드의 명확성에서

if(a & 0x2) /* etc */ 

은 비트 필드가 깔끔한 것을 나에게 매우 명백하다. 그러나 어떤 옵션이 더 빠릅니까? 나는 속도 차이가 너무 많지 않을 것이라는 것을 안다. 그러나 내가 그 중 하나를 사용할 수 있다면, 더 빨리, 더 좋다면 좋다.
다른 한편으로는, 비트 필드가 플랫폼간에 동일한 순서로 비트 정렬을 보장하지 않는다는 점을 읽었습니다. 코드를 이식 가능하게 만들고 싶습니다.

참고 : '프로필'에 답할 계획이면 괜찮습니다. 그러나 나는 게으르다. 이미 누군가가 대답을하면 훨씬 좋습니다.
코드가 잘못되었을 수 있습니다. 원할 경우 수정할 수 있지만이 질문에 대한 요점을 기억하고 시도해보십시오.

+0

http://stackoverflow.com/questions/1044654/bitfield-manipulation-in-c에 관심이있을 수 있습니다. 적어도 내가 생각하는 또 다른 매우 유사한 질문이 있습니다 (이 것은이 것 같지 않습니다). –

+0

Bitfields : 너 야! 모두에게 감사드립니다. – Petruza

+0

와우. 우리는 여기서 중요한 교훈을 가르쳤습니다. –

답변

6

차라리 두 번째 예제를 사용하여 최대 이식성을 선호합니다. Neil Butterworth가 지적했듯이 비트 필드를 사용하는 것은 원시 프로세서에만 해당됩니다. 알았어, 이것에 대해 생각해 보라. 인텔의 x86이 내일 폐업 될 경우 어떻게 될까? 코드는 고착 될 것이다. 이것은 다른 프로세서를위한 비트 필드를 다시 구현해야한다는 것을 의미한다.

더 큰 그림을보고 OpenBSD가 하나의 코드베이스를 사용하여 많은 BSD 시스템을 여러 플랫폼으로 이식하는 방법을 묻지 않았습니까? 좋아, 내가 조금 넘어서고, 논쟁의 여지가없고 주관적이지만, 현실적으로 말하면, 코드를 다른 플랫폼으로 이식하려는 경우, 질문에 사용한 두 번째 예제를 사용하여 코드를 이식하는 방법입니다. .

다른 플랫폼 용 컴파일러는 컴파일러가있는 프로세서의 비트 필드를 정렬하는 자체적 인 패딩 방법을 가지고 있습니다. 게다가 프로세서의 엔디안은 어떻습니까?

비트 필드를 마법의 탄환으로 사용하지 마십시오. 프로세서의 속도를 원한다면 (즉, 포팅 할 의도가 없다면) 비트 필드를 자유롭게 사용하십시오. 둘 다 가질 수 없습니다!

+0

+1 : 포팅 할 의도가 없다는 것만이 아닙니다. 한 프로세서의 메모리가 아닌 모든 컨텍스트에서 변수의 전체 내용을 정수 (대 개인 비트)로 사용할 의사가 없습니다. 비트 필드 구조의 정수 값을 디스크, 네트워크 또는 일부 내장 시스템 주변 장치로 보내면 컴파일러가 비트 필드를 적절한 순서로 배치해야합니다. –

+6

수동으로 정의 된 비트 필드를 통해 내장 된 비트 필드를 사용하는 것이 더 이식성이 있다는 사실을주의하십시오. 구조체의 메모리 레이아웃이 매우 특정한 방식으로 설정되어 있다면 믿을 수 있습니다.하지만 모두 내장 된 구문을 통해 각 필드에 액세스하면 모든 이식성 문제가 발생하지 않습니다. –

+0

부모가 잘못되었거나 CPU 이식성 문제가 아니라 컴파일러 이식성 문제입니다. 각 컴파일러는 원하는대로 비트 필드를 정렬 할 수 있으므로 서로 다른 컴파일러로 컴파일 된 코드가 서로 올바르게 링크되고 비트 필드가 포함 된 데이터를 공유 할 수 없습니다. 마스킹 및 이동을 수행하면이 문제가 해결됩니다. – naasking

4

휴대 성을 원하면 bitfields를 피하십시오. 특정 코드의 성능에 관심이 있다면 테스트를 직접 작성할 수 없습니다. 비트 필드는 프로세서의 비트 명령어를 사용합니다.

+0

비트 필드 순서 이외에 비트 필드를 옮길 수없는 이유는 무엇입니까? 또한 일부 프로세서는 비트 필드 삽입/추출을 지원합니다. 예를 들어, 68020이 그랬습니다. –

+3

포장 문제도 있습니다. 그리고 프로세서가 특수 목적의 명령어를 가지고 있기 때문에 컴파일러가이 명령어를 사용한다는 보장이 없기 때문에 테스트가 필수라고 말한 것입니다. –

+2

아, 단지 비트 필드가 구현에 따라 더 많거나 적은 공간을 사용하기 때문에 이식성이 떨어지지 않기 때문입니다. 그리고 컴파일러가 프로세서가 할 수있는 것을 이용하지 않는다면, 그것을 개선하거나 대체해야합니다. –

1

C 프로그래머는 비트 마스크 및 논리 연산을 사용하여 각 비트의 값을 추론하는 두 번째 옵션을 선호한다고 생각합니다. 코드가 16 진수 값으로 흩어져있는 대신 열거 형이 설정되거나 대개 복잡한 작업이 포함될 때 매크로를 사용하여 특정 비트를 가져 오거나 설정합니다. grapevine에 대해 들었습니다. 구현 된 비트 필드는 느립니다.

+0

요점은 비트 필드가 여러 플랫폼에서 순서대로 작동한다는 보장이 없습니다. 따라서 하드웨어 레지스터에 비트 필드를 사용하는 경우 하드웨어가 왜 필요한 작업을 수행하지 못하는지 디버깅하는 것이 매우 어려울 것입니다. –

5

구조체를 변경하면 두 번째 표현식이 잘못 될 수 있기 때문에 첫 번째 표현식과 두 번째 표현식의 속도는 모두 오류가 발생하기 쉽습니다.

첫 번째 문자를 사용하십시오.

+0

아니요. 첫 번째 코드는 대부분의 코드 작성자가 절대 만지지 않고 이해할 수없는 비정상적인 기능을 사용합니다. 두 번째 코드는 보통 관용적 인 C입니다. 따라서 두 번째 옵션은 의도에 대해 명확하며 부주의로 인해 쉽게 손상되지 않습니다. 관리자. – Porculus

+0

두 번째 표현식에 잘못된 점은 개발자가 의미하는 바를 알 수 있도록 '0x02'가 정의 된 상수 일 필요가 있다는 것입니다. 첫 번째 문제는 컴파일러가 두 비트를 8 비트 바이트에 넣을 수 있다는 것입니다. 리눅스 커널은 비트 순서 (bit order)와 패킹 (packing)을 선언하기위한 전체 상수 세트를 정의하고 있기 때문에'# ifdef' 블록을 유지하기가 어렵다. 그리고 플랫폼은'char '을 8 비트로 정의한다고 가정합니다. 나는 DSP가 바이트, 단지 단어를 처리 할 수 ​​없기 때문에'char'를 16 비트로 정의한 플랫폼 용으로 개발했습니다. –

12

비트 필드를 적절하게 사용하면 코드가 훨씬 명확 해집니다. 나는 비트 필드를 공간 절약 장치로만 사용할 것입니다. 필자가 보았던 공통점은 컴파일러에 있습니다. 유형 또는 기호 정보는 흔히 true/false 플래그로 구성됩니다. 비트 필드는 컴파일 할 때 일반적인 프로그램에 수천 개의 노드가 생성되므로 이상적입니다.

일반적인 임베디드 프로그래밍 작업을 수행하기 위해 비트 필드를 사용하지 않습니다 : 장치 레지스터 읽기 및 쓰기. 문서에서 필요로하는 비트를 정확히 얻을 수 있고 비트 필드의 다양한 컴파일러 구현의 차이점에 대해 걱정할 필요가 없으므로 여기에서 교대조와 마스크를 사용하는 것이 더 좋습니다.

속도면에서 좋은 컴파일러는 마스킹 할 비트 필드에 대해 동일한 코드를 제공합니다.

+0

비트 필드를 사용할 때의 문제는 공간을 절약 할 수 있다는 보장이 없다는 것입니다. 컴파일러는 int 인 것처럼 각 비트 필드에 32 비트를 할당 할 수 있습니다. 왜 그럴까? 대부분의 경우 더 빠릅니다. – jalf

+0

오른쪽. 하지만 공간을 절약 할 수 있습니다. 많은 똑똑한 사람들은 비트 필드를 이용하여이를 수행합니다. –

+0

@jaif : 나는 BS에 전화한다. 당신은 그 주장을 뒷받침하는 어떤 것을 가지고 있습니까, 나는 그 스펙을보기에는 너무 게으르지 만, 그것이 허락된다는 것을 정말로 의심합니다. – SoapBox

6

C 비트 필드는 알려지지 않은 이유로 발명 된 순간부터 사산되었습니다. 사람들은 그 (것)들을 좋아하지 않으며 대신에 비트 연산자를 사용했습니다. 다른 개발자가 C 비트 필드 코드를 이해하지 못하게해야합니다.

더 빠른 것은 관련이 없습니다. 관련 없음. 모든 최적화 컴파일러 (실제로 모든 것을 의미)는 코드가 어떤 표기법에서도 동일한 것을 수행하게합니다. 컴파일러가 키워드를 검색하여 어셈블리로 대체한다는 것은 C 프로그래머에게 흔히있는 오해입니다. 현대 컴파일러는 소스 코드를 청사진으로 사용하여 달성해야 할 사항을 파악한 다음 종종 매우 다르게 보이지만 의도 한 결과를 얻는 코드를 내 보냅니다.

1

"휴대용이 아닌 비트 필드"는 많이 읽지 마십시오. 구현 된 비트 필드의 두 가지 측면, 즉 부호와 레이아웃과 하나의 지정되지 않은 것 : 패킹되어있는 할당 단위의 정렬. 두 개의 비트 필드 구현이 정의됩니다. 패킹 효과가 필요하지 않은 경우에는 불특정 속성을 갖는 함수 호출로 이식성이 있습니다 (필요할 경우 signed 키워드를 명시 적으로 지정하는 경우).

성능과 관련하여 프로필은 가장 좋은 답변입니다. 완전한 세계에서,이 두 저술 사이에는 아무런 차이가 없을 것이다. 실제로는 몇 가지가있을 수 있지만 한 방향으로 다른 이유만큼 많은 이유를 생각할 수 있습니다. 그리고 문맥 (서명되지 않은 것과 서명 된 것 사이의 논리적으로 의미없는 차이)은 문맥에 매우 민감 할 수 있으므로 문맥 상 매우 중요합니다 ...

요약하면, 차이점은 실제로 선택의 여지가있는 경우의 스타일 차이입니다 (즉, 정확한 레이아웃이 중요하지 않은 경우). 이러한 경우 최적화 (속도가 아닌 크기)이므로 먼저 코드없이 코드를 작성하고 필요할 경우 추가하는 경향이 있습니다. 따라서 비트 필드가 확실한 선택입니다 (수행 할 수정 사항은 결과를 얻기위한 가장 작은 수정이며 모든 사용 장소로 확산되는 대신 정의의 고유 한 위치에 포함됩니다).

관련 문제