2013-02-27 14 views
13

Kiedy używamy prefiksu 0x dla liczb szesnastkowych i o dla liczb ósemkowych, czy jest coś, co można zrobić dla liczb binarnych?Pisanie systemu liczb binarnych w kodzie C

Próbowałem przyrostka b, ale GCC na to nie zezwolił.

Error: invalid suffix "b" on integer constant

Czy to możliwe?

+3

Literały binarne nie istnieją w C. Najbliższe są szesnastkowe, ponieważ ściśle podążają za binarnym wzorem bitowym. –

+1

Hex na binarny jest bardzo łatwy do konwersji. –

+0

Oktal jest również dostępny, napisany 0666 i tak (/ moje kaczki i działa) – vonbrand

Odpowiedz

30

Standard C nie definiuje stałych binarnych. Jest GNU (wierzę) rozszerzenie chociaż (wśród popularnych kompilatorów, dzyń dostosowuje je również): the 0b prefix:

int foo = 0b1010; 

Jeśli chcesz trzymać się standardowej C, to nie ma opcji: można połączyć makro i funkcją stworzyć prawie czytelny „binarny” stałą cechę:

#define B(x) S_to_binary_(#x) 

static inline unsigned long long S_to_binary_(const char *s) 
{ 
     unsigned long long i = 0; 
     while (*s) { 
       i <<= 1; 
       i += *s++ - '0'; 
     } 
     return i; 
} 

i wtedy można go używać tak:

int foo = B(1010); 

Jeśli włączysz optymalizację kompilatorów, najprawdopodobniej kompilator najprawdopodobniej całkowicie wyeliminuje wywołanie funkcji (stałe składanie) lub przynajmniej je podkreśli, więc nie będzie to nawet problem z wydajnością.

Dowód:

Poniższy kod:

#include <stdio.h> 
#include <stdlib.h> 
#include <limits.h> 
#include <string.h> 


#define B(x) S_to_binary_(#x) 

static inline unsigned long long S_to_binary_(const char *s) 
{ 
    unsigned long long i = 0; 
    while (*s) { 
     i <<= 1; 
     i += *s++ - '0'; 
    } 
    return i; 
} 

int main() 
{ 
    int foo = B(001100101); 

    printf("%d\n", foo); 

    return 0; 
} 

został skompilowany przy użyciu clang -o baz.S baz.c -Wall -O3 -S i wyprodukowany następujący montaż:

.section __TEXT,__text,regular,pure_instructions 
    .globl _main 
    .align 4, 0x90 
_main:         ## @main 
    .cfi_startproc 
## BB#0: 
    pushq %rbp 
Ltmp2: 
    .cfi_def_cfa_offset 16 
Ltmp3: 
    .cfi_offset %rbp, -16 
    movq %rsp, %rbp 
Ltmp4: 
    .cfi_def_cfa_register %rbp 
    leaq L_.str1(%rip), %rdi 
    movl $101, %esi    ## <= This line! 
    xorb %al, %al 
    callq _printf 
    xorl %eax, %eax 
    popq %rbp 
    ret 
    .cfi_endproc 

    .section __TEXT,__cstring,cstring_literals 
L_.str1:        ## @.str1 
    .asciz "%d\n" 


.subsections_via_symbols 

Więc clang całkowicie wyeliminowane wywołanie funkcja i zastąpił jej wartość zwracaną przez 101. Schludnie, co?

+0

Następne pytanie brzmi: dlaczego napisałeś 'foo = [długi bałagan liczb binarnych]' zamiast 'foo = CONSTANT1 | CONSTANT2 | ...; '. Co osiągnął numer binarny? – Lundin

+5

@Lundin Huh? Chodzi o czytelność i posiadanie ** literałów binarnych **. –

+0

A moim celem jest to, że nie ma sytuacji, w której literały binarne są bardziej czytelne niż coś innego, bardziej odpowiednie, takie jak # zdefiniowane maski bitowe. – Lundin

5

przedrostek dosłowne z 0b jak w

int i = 0b11111111; 

Zobacz here.

+8

Jest to rozszerzenie i może potrzebować specjalnej flagi dla 'gcc', aby to zrozumieć. I oczywiście nie jest przenośny dla innych kompilatorów, które nie obsługują tego rozszerzenia. –

5

Użyj BOOST_BINARY (Tak, możesz użyć go w C).

#include <boost/utility/binary.hpp> 
... 
int bin = BOOST_BINARY(110101); 

To makro jest rozszerzane do ósemkowego dosłowności podczas wstępnego przetwarzania.