标准C并没有定义二进制常量。不过,GNU C提供了一个扩展(在流行的编译器中,clang也支持它):使用0b
或0B
前缀:
int foo = 0b1010;
#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 foo = B(1010);
#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;
}
使用clang -o baz.S baz.c -Wall -O3 -S
编译后,生成以下汇编代码:
.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
clang
完全消除了对函数的调用,并将其返回值替换为101
。很整洁,是吧?11001001101
比读取0xc02
更容易。我不知道这对你有什么影响,但对我来说,十六进制字面量的二进制表示并不是一眼就能看出来的。也许对你来说很明显。 - user529758gcc
的特殊标志才能理解。当然,在不支持该扩展功能的其他编译器上无法移植。 - Some programmer dude使用BOOST_BINARY库(是的,你可以在C语言中使用它)。
#include <boost/utility/binary.hpp>
...
int bin = BOOST_BINARY(110101);
在预处理期间,此宏将扩展为八进制字面量。