sourcetip

C 표준 방식으로 비트 표현을 하는 방법은?

fileupload 2023. 10. 30. 21:13
반응형

C 표준 방식으로 비트 표현을 하는 방법은?

C 표준에 따라 정수형의 값 표현은 정의되어 있습니다. 그래서5로 표현되지 않을 수도 있습니다.00000000000000000000000000000101아니면-1~하듯이11111111111111111111111111111111우리가 보통 32비트 2의 보어로 가정하듯이.그래서 운영자들이~,<<그리고.>>잘 정의되어 있으며, 이들이 작업할 비트 패턴은 구현이 정의되어 있습니다.정의된 비트 패턴은 " §5.2.1/3 모든 비트가 0으로 설정된 null 문자라고 불리는 바이트가 기본 실행 문자 집합에 존재해야 합니다. 문자열을 종료하는 데 사용됩니다."뿐이었습니다.

그래서 제 질문은 - 정수형을 비트 패턴으로 변환하는 구현 독립적인 방법이 있나요?

항상 null 문자로 시작해서 원하는 값을 얻을 수 있을 정도의 비트 연산을 수행할 수 있지만 너무 번거롭습니다.또한 실질적으로 모든 구현이 2의 보완 표현을 사용할 것이라는 것을 알고 있지만 순수한 C 표준 방식으로 수행하는 방법을 알고 싶습니다.개인적으로 지금까지 작성된 모든 코드가 특정 구현을 가정하는 장치 드라이버 프로그래밍 문제 때문에 이 주제는 꽤 흥미롭습니다.

일반적으로 일반적인 플랫폼을 수용하는 것은 그리 어렵지 않습니다(단순히 8비트라고 가정하지 않으려면).char, 2의 보완, 패딩 없음, 트랩 없음, 잘라내기 비부호-서명 변환 등의 기능을 갖춘 표준은 대부분 충분한 보장을 제공합니다(특정 구현 세부 정보를 검사하기 위한 매크로 몇 개가 도움이 될 것입니다).

엄격하게 일치하는 프로그램이 관찰할 수 있는 한(비트 필드 외부에서), 5는 항상 다음과 같이 인코딩됩니다.00...0101이할 수 있는 이것은 반드시 물리적 표현(이것이 무엇을 의미하든 간에)이 아니라 휴대용 코드로 관찰할 수 있는 것입니다.예를 들어 내부적으로 그레이 코드를 사용하는 기계는 비트 와이즈 연산자 및 시프트에 대한 "순수 이진 표기법"을 에뮬레이트해야 합니다.

부호화된 유형의 음수 값의 경우 서로 다른 인코딩이 허용되며, 이로 인해 해당하는 부호화되지 않은 유형으로 다시 해석할 때 다른(모든 경우에 대해 잘 정의된) 결과가 나타납니다.예를 들어, 엄격하게 준수하는 코드는 다음을 구별해야 합니다.(unsigned)n그리고.*(unsigned *)&n부호가 있는 정수에 대하여n: 이들은 패딩 비트가 없는 2의 보어에 대해서는 동일하지만, 만일 다음과 같은 경우에 다른 부호화에 대해서는 다릅니다.n음입니다.

또한 패딩 비트가 존재할 수 있으며, 부호화된 정수 타입은 대응하는 비부호 대응 타입보다 패딩 비트 수가 더 많을 수 있습니다. (그러나 그 반대는 아니지만, 부호에서 비부호로의 타입-펀닝은 항상 유효합니다.)sizeofpadding가 아닌 비트의 수를 가져오는 데 사용할 수 없으므로, (해당하는 부호 유형의) 부호 비트만 설정된 부호 없는 값을 얻으려면 다음과 같은 것을 사용해야 합니다.

#define TYPE_PUN(to, from, x) ( *(to *)&(from){(x)} )
unsigned sign_bit = TYPE_PUN(unsigned, int, INT_MIN) &
                    TYPE_PUN(unsigned, int, -1) & ~1u;

(아마도 더 좋은 방법이 있을 것입니다) 대신에

unsigned sign_bit = 1u << sizeof sign_bit * CHAR_BIT - 1;

폭보다 더 많이 이동할 수 있기 때문입니다. (폭을 나타내는 상수 표현은 모르지만,sign_bit위에서 0이 될 때까지 오른쪽으로 이동하여 결정할 수 있습니다. Gcc는 이를 일정하게 접을 수 있습니다.)패딩 비트는 다음과 같이 검사할 수 있습니다.memcpy에 들어가기unsigned char배열은 "wobble"처럼 보일 수 있지만: 같은 패딩 비트를 두 번 읽는 것은 다른 결과를 줄 수 있습니다.

부호가 있는 정수(작은 엔디언)의 비트 패턴(패딩 비트 없음)을 원하는 경우:

int print_bits_u(unsigned n) {
    for(; n; n>>=1) {
        putchar(n&1 ? '1' : '0'); // n&1 never traps
    }
    return 0;
}

int print_bits(int n) {
    return print_bits_u(*(unsigned *)&n & INT_MAX);
    /* This masks padding bits if int has more of them than unsigned int.
     * Note that INT_MAX is promoted to unsigned int here. */
}

int print_bits_2scomp(int n) {
    return print_bits_u(n);
}

print_bits사용된 표현에 따라 음수에 대해 다른 결과를 제공합니다(원시 비트 패턴을 제공함).print_bits_2scomp2의 보어 표현(폭이 a보다 큰 possibly)을 제공합니다.signed int가 있다면, 만일unsigned int패딩 비트(padding bits)가 적습니다.

비트 와이즈 연산자를 사용할 때와 서명되지 않은 연산자에서 서명된 연산자로 유형 펀칭할 때 트랩 표현이 생성되지 않도록 주의해야 합니다. 아래에서 이러한 표현이 생성될 가능성이 있는 방법을 참조하십시오(예:*(int *)&sign_bit두 개의 보어로 덫을 놓을 수 있고,-1 | 1자신의 보배를 함정에 빠뜨릴 수 있습니다).

비부호-서명 정수 변환(변환된 값이 대상 유형에서 표현할 수 없는 경우)은 항상 구현 정의됩니다. 기술적으로는 2의 보완 시스템이 일반적인 정의와 다를 가능성이 높지만, 2의 보완 구현에서 문제가 될 수도 있습니다.

C11(n1570) 6.2.6.2부터:

(1) 다음 이외의 부호 없는 정수 유형의 경우unsigned char, 객체 표현의 비트는 값 비트와 패딩 비트(padding bits)의 두 그룹으로 나뉩니다. (뒤의 것은 있을 필요가 없습니다.)N개의 값 비트가 있는 경우 각 비트는 1과 2 사이N-1 2의 서로 다른 거듭제곱을 나타내야 하며, 따라서 해당 유형의 객체는 순수 이진 표현을 사용하여 0에서 2-1N 사이의 값을 나타낼 수 있어야 합니다. 이를 값 표현이라고 합니다.패딩 비트의 값은 지정되지 않습니다.

(2) 부호가 있는 정수형의 경우 객체 표현의 비트를 값 비트, 패딩 비트, 부호 비트의 세 그룹으로 나눕니다.패딩 비트가 있을 필요는 없습니다.signed char패딩 비트가 없어야 합니다.기호 비트가 정확히 하나일 것입니다.값 비트인 각 비트는 해당 비부호 유형의 객체 표현에서 동일한 비트와 동일한 값을 가져야 합니다(부호 유형에 M 값 비트가 있고 비부호 유형에 N 비트가 있으면 M≤N입니다).부호 비트가 0이면 결과 값에 영향을 주지 않습니다.부호 비트가 1이면 다음 중 하나의 방법으로 값을 수정해야 합니다.

  • 부호 비트가 0인 해당 값은 음수입니다(부호크기).
  • 부호 비트는 -(2M)(2의 보어) 값을 갖습니다;
  • 부호 비트는 -(2-1M) 값을 갖습니다(자신의 보어).

부호 비트가 1이고 모든 값 비트가 0인 값(처음 두 개의 경우) 또는 부호 비트와 모든 값 비트가 1인 값(자신의 보어인 경우)이 트랩 표현인지 정규 값인지 여부와 마찬가지로 이 중 어느 것이 적용되는지가 구현에 정의됩니다.부호와 크기 그리고 보의 경우, 이 표현이 정상 값이면 음의 0이라고 합니다.

mafso의 훌륭한 답변에 덧붙이자면, ANSIC의 이론적 근거의 일부가 이에 대해 이야기합니다.

위원회는 C 언어를 바이너리 아키텍처로 명시적으로 제한하였는데, 이는 이 제약이 어떤 경우에도 암시적이었다는 것을 근거로 합니다.

  • 비트 필드는 "잘못된 정수" 표현에 대한 언급 없이 비트 수로 지정됩니다.이러한 비트 필드에 적합한 유일한 인코딩은 이진입니다.
  • printf의 정수 형식은 "잘못된 정수" 값에 대한 규정이 없음을 의미하며, 이는 비트 와이즈 조작의 결과가 printf에 의해 인쇄될 수 있는 정수 결과를 생성함을 의미합니다.
  • 정수 상수를 지정하는 모든 방법(10진수, 16진수 및 8진수)은 정수 값을 지정합니다."비트 문자열 상수"를 지정하기 위해 정수와 독립적인 메서드가 정의되지 않았습니다.이진 인코딩만이 비트 문자열과 정수 값 사이의 완전한 일대일 매핑을 제공합니다.

이진 숫자 시스템에 대한 제한은 그레이 코드와 같은 호기심을 배제하고 부호 없는 유형에서 비트 와이즈 연산자의 산술 정의를 가능하게 합니다.

표준과 관련된 부분은 다음 인용문이 될 수 있습니다.

3.1.2.5 종류

[...]

type char, signed 및 unsigned 정수 type 및 열거된 type을 통합 type이라고 합니다.적분 형식의 표현은 순수 이진법 숫자 체계를 사용하여 값을 정의해야 합니다.

주어진 비트 패턴을 얻으려면int, 그러면 비트 와이즈 연산자는 당신의 친구입니다.변환하려면int그것의 2-comple 표현에 따르면, 산술 연산자는 당신의 친구입니다.구현이 정의되었기 때문에 두 가지 표현은 다를 수 있습니다.

2011.6.5/4 표준 초안.일부 연산자(단항 연산자 ~ 및 이진 연산자 <<, >> &, ^ 및 |, 비트 와이즈 연산자로 통칭됨)는 정수형을 갖는 피연산자를 가져야 합니다.이러한 연산자는 정수의 내부 표현에 따라 달라지는 값을 산출하고, 서명된 유형에 대해 구현 정의 및 정의되지 않은 측면을 갖습니다.

그러니까 말입니다.i<<1비트 pattern를 효과적으로 왼쪽으로 한 위치 이동시키지만 생성된 값은 다음과 다를 수 있습니다.i*2(작은 값의 경우에도)i).

언급URL : https://stackoverflow.com/questions/28937523/how-to-do-a-bit-representation-in-a-c-standard-way

반응형