programing

왜 C는 2진법을 가지고 있지 않은가?

prostudy 2022. 5. 13. 23:48
반응형

왜 C는 2진법을 가지고 있지 않은가?

나는 종종 c:에서 이런 것을 할 수 있기를 바란다.

val1 &= 0b00001111; //clear high nibble
val2 |= 0b01000000; //set bit 7
val3 &= ~0b00010000; //clear bit 5

이런 구문을 갖는 것은 내가 생각할 수 있는 단점이 없는 C에 믿을 수 없을 정도로 유용한 덧셈인 것 같고, 사소한 말다툼이 꽤 흔한 저급한 언어에 있어서는 당연한 일인 것 같다.

편집: 나는 다른 훌륭한 대안들을 보고 있지만 더 복잡한 마스크가 있을 때 그것들은 모두 무너진다.예를 들어, 다음과 같다.reg마이크로컨트롤러의 I/O 핀을 제어하는 레지스터인데, 핀 2, 3, 7을 동시에 높게 설정하고 싶다.reg = 0x46;하지만 나는 그것에 대해 10초를 생각하면서 보내야 했다. (그리고 나는 하루나 이틀 동안 보지 않고 그 코드를 읽을 때마다 10초를 다시 써야 할 것 같다.) 또는 나는 쓸 수 있었다.reg = (1 << 1) | (1 << 2) | (1 << 6);하지만 개인적으로 나는 그것이 단순히 'regage = 0b01000110'을 쓰는 것보다 훨씬 덜 명확하다고 생각한다; 나는 그것이 8비트 또는 16비트 아키텍처 이상으로 잘 확장되지 않는다는 것에 동의한다.32비트 마스크를 만들 필요가 없었던 건 아니에요.

국제 표준 이론에 따라 - 프로그래밍 언어 C §6.4.1 정수

선례가 부족하고 효용이 불충분하여 이진수 상수를 추가하자는 제안이 부결되었다.

표준 C에는 없지만 GCC는 이를 확장자로 지원하고 있으며, 앞에 다음과 같이 되어 있다.0b또는0B:

 i = 0b101010;

자세한 내용은 여기를 참조하십시오.

당신의 모든 예는 훨씬 더 명확하게 쓰여질 수 있다.

val1 &= (1 << 4) - 1; //clear high nibble
val2 |= (1 << 6); //set bit 6
val3 &=~(1 << 3); //clear bit 3

(나는 자연의 의도대로 0부터 세도록 코멘트를 수정하는 자유를 누렸다.)

컴파일러는 이 상수를 접을 것이므로, 이렇게 쓰면 성능 저하가 없다.그리고 이것들은 보다 읽기 쉽다.0b...판본

이게 16진법을...16진법의"... 16진법 표기법의 일차적 용도는 컴퓨팅과 디지털 전자제품에서 이진법 코드 값을 인간 친화적으로 표현한 것이다.다음과 같을 것이다.

val1 |= 0xF;
val2 &= 0x40;
val3 |= ~0x10;

16진수:

  1. 하나의 16진수는 니블(4비트 또는 1/5 옥탈)을 나타낼 수 있다.
  2. 두 개의 16진수는 1바이트(8비트)를 나타낼 수 있다.
  3. 16진법은 대형 마스크로 스케일링할 때 훨씬 콤팩트하다.

어떤 연습이 있으면, 16진법과 2진법 사이의 변환은 훨씬 더 자연스러워질 것이다.변환을 손으로 작성하고 온라인 빈/헥스 표기 변환기를 사용하지 마십시오. 그러면 며칠 내로 변환이 자연스러워질 것입니다(결과적으로 더 빠름).

별도로: 2진수 리터럴이 C 표준은 아니지만 GCC로 컴파일할 경우 2진수 리터럴을 사용할 수 있다면 '0b' 또는 '0B'로 접두사를 붙여야 한다.자세한 내용은 공식 문서를 참조하십시오.예:

int b1 = 0b1001; // => 9
int b2 = 0B1001; // => 9

나는 가독성이 주요 관심사라고 생각한다.비록 낮은 수준이지만, 기계가 아니라 당신의 코드를 읽고 유지하는 것은 인간이다.

?0b1000000000000000000000000000000(0x40000000), 당신이 진심으로 말하는 곳0b10000000000000000000000000000000(0x80000000)?

컴파일러 경고나 다른 문제를 피하려면 C에 있는 C 매크로를 추천한다.0x 대신 Ohio를 사용한다.

#define Ob00000001 1
#define Ob10000000 (1 << (8-1))
#define Ob00001111 15
#define Ob11110000_8 (Ob00001111 << (8 - 4))
#define Ob11110000_16 (Ob00001111 << (16 - 4))
#define Ob11110000_32 (((uint32_t) Ob00001111) << (32 - 4))
#define Ob11110000_64 (((uint64_t) Ob00001111) << (64 - 4))
#define Ox0F Ob00001111
#define OxF0 Ob11110000_8
#define OxF000 Ob11110000_16
#define OxF0000000 Ob11110000_32
#define OxF000000000000000 Ob11110000_64

int main() {
    #define Ob00001110 14
    // bitwise operations work
    if (Ob00001110 == (Ob00001111 & ~Ob00000001)) {
        printf("true\n");
    }
}

제 접근 방식은 다음과 같았다.

/* binmacro.h */

#define BX_0000 0
#define BX_0001 1
#define BX_0010 2
#define BX_0011 3
#define BX_0100 4
#define BX_0101 5
#define BX_0110 6
#define BX_0111 7
#define BX_1000 8
#define BX_1001 9
#define BX_1010 A
#define BX_1011 B
#define BX_1100 C
#define BX_1101 D
#define BX_1110 E
#define BX_1111 F

#define BIN_A(x) BX_ ## x

#define BIN_B(x,y) 0x ## x ## y
#define BIN_C(x,y) BIN_B(x,y)

#define BIN_B4(x,y,z,t) 0x ## x ## y ## z ## t
#define BIN_C4(x,y,z,t) BIN_B4(x,y,z,t)

#define BIN(x,y) BIN_C(BIN_A(x),BIN_A(y))
#define BIN4(x,y,z,t) BIN_C4(BIN_A(x),BIN_A(y),BIN_A(z),BIN_A(t))

/*---- test ... ---*/

BIN(1101,0100)

BIN4(1101,0010,1100,0101)

다음 단계로 넘어가면...

$  cpp binmacro.h
0xD4

0xD2C5

바이너리는 컨트롤러에서 특정 출력을 설정할 때 가장 유용하다.나는 기술적으로는 불법이지만 그럼에도 불구하고 항상 효과가 있는 해킹을 사용한다.만약 당신이 LED를 켜기만 하면 모든 감성을 상하게 할 수 있고, 심지어 그 일을 위해 차자를 사용할 수도 있다.우리가 아마도 이런 것들에 대한 편집 정교함의 궁극적인 부분에 대해 이야기하고 있지 않다는 것을 잊지 마십시오.그룹 제어와 결합된 개별적인 정보성을 위해 비트필드:-를 사용한다.

struct DEMAND
{
    unsigned int dOil   :   1; // oil on
    unsigned int dAir   :   1; // air on
    unsigned int dHeat  :   1; // heater on
    unsigned int dMtr1  :   1; // motor 1 on
    unsigned int dMtr2  :   1; // motor 2 on
    unsigned int dPad1  :   10;// spare demand o/p's
    unsigned int dRunCycle: 1; // GO !!!!
    unsigned int dPad2  :   15;// spare o/p's
    unsigned int dPowerOn:  1; // Power on
}DemandBF;

그것들은 단독으로 사용할 때 쉽게 다루어지거나, 좀 더 철저한 관리를 위해 K&R:-를 노골적으로 무시한 채 서명되지 않은 것으로 취급될 수 있다.

void *bitfPt = &DemandBF;
unsigned int *GroupOuts = (unsigned int *)bitfPt;

DemandBF.dAir = 1;   // Clearly describes what's turning on
DemandBF.dPowerOn = 1;

*GroupOuts ^= 0x04; // toggle the heater

*GroupOuts = 0; // kill it all

나한테는 항상 먹혔어, 아마 휴대할 수 없을 거야, 근데 누가 이런 걸 실제로 항구로 옮기겠어?한번 해 봐라.

"예를 들어 레지스터가 마이크로컨트롤러의 I/O 핀을 제어하는 레지스터인 경우"

나는 이것이 나쁜 예라고 생각하지 않을 수 없다.제어 레지스터의 비트에는 특정 기능이 있다(개별 IO 비트에 연결된 모든 장치가 그러하듯이).

코드 내에서 이진수를 계산하는 것보다 헤더 파일에서 비트 패턴에 대한 기호 상수를 제공하는 것이 훨씬 합리적일 것이다.바이너리를 16진수 또는 8진수로 변환하는 것은 사소한 일이며, 특히 데이터시트나 회로도가 없는 경우 IO 레지스터에 01000110을 쓸 때 어떤 일이 일어나는지 기억하십시오.

그러면 바이너리 코드를 계산하기 위해 10초를 절약할 수 있을 뿐만 아니라, 그것이 무엇을 하는지 알아내려고 하는 시간이 다소 더 길어질 수도 있다!

다음은 확장하기 쉬워야 하지만 8비트로 제한된다.C 리터럴이 되지는 않지만, 컴파일 시간 상수가 된다.

#define B_(X) B8_("00000000" #X)
#define B8_(X) B8__(X+sizeof(X)-9)
#define B8__(X) \
        (B___((X), 7) | B___((X), 6) | B___((X), 5) | B___((X), 4) | \
         B___((X), 3) | B___((X), 2) | B___((X), 1) | B___((X), 0))
#define B___(X, I) (((X)[7-(I)] - '0') << (I))

다음 함수는 상수를 반환하는 코드로 컴파일된다.18.

int test(void) {
    return B_(10010);
}

온라인으로 해봐!

성능이 문제가 되지 않는 경우 다음과 같은 간단한 작업을 수행하십시오.

#define B_(x) strtoull(#x, 0, 2)

참조URL: https://stackoverflow.com/questions/18244726/why-doesnt-c-have-binary-literals

반응형