用C代码编写二进制数系统

cip*_*her 23 c

因为我们使用0x十六进制数字的前缀,0对于八进制数字,是否可以为二进制数字做任何事情?

我尝试了b后缀,但GCC不允许这样做.

错误:整数常量上的后缀"b"无效

可能吗?

小智 49

标准C不定义二进制常量.虽然有一个GNU(我相信)扩展(在流行的编译器中,clang也适应它):0b前缀:

int foo = 0b1010;
Run Code Online (Sandbox Code Playgroud)

如果你想坚持标准C,那么有一个选项:你可以结合一个宏和一个函数来创建一个几乎可读的"二进制常量"功能:

#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;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

int foo = B(1010);
Run Code Online (Sandbox Code Playgroud)

如果你打开繁重的编译器优化,编译器很可能完全消除函数调用(常量折叠)或至少内联它,所以这甚至不会成为性能问题.

证明:

以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

已经编译使用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
Run Code Online (Sandbox Code Playgroud)

因此clang完全取消了对函数的调用,并用其替换了它的返回值101.整洁,对吧?

  • @Lundin我反驳过这个吗?OP问"这怎么可能",我已经向他展示了如何.是时候离开我了. (10认同)
  • @Lundin嗯?关键是可读性和**二进制文字**. (9认同)
  • @Lundin在很多情况下,很多人会发现二进制数字更具可读性.实际上,在定义包含大量标志的枚举时,许多程序员将在注释中使用其二进制值来注释每个常量.事实上,现在C++提供了用户定义的文字,许多人实现的第一个是二进制数字文字的扩展. (9认同)
  • @Lundin - 从那些使用过大量嵌入式硬件的人那里得到它:在CPU的数据总线方面,我们经常不得不处理二进制值,这些二进制值不是从位0的低位开始.当然,在这种情况下,获取值并为其移动它的宏非常有用并处理可读性问题,有时能够简单地指定二进制文字是很好的.我发现随着我越来越习惯于嵌入式编程,我对二进制文字的"需要"已经降到接近零,但在开始时他们看起来似乎很方便. (4认同)
  • @Lundin 你没有明白这一点。有些人认为八进制和十六进制文字就足够了 - 虽然它们已经足够了,但如果想要一种位模式,读取“11001001101”比“0xc02”更容易 - 我不知道这可能会让你担心,但对我来说,十六进制文字的二进制表示形式乍一看并不明显。也许适合你。 (2认同)

bas*_*h.d 13

使用0b像in中的文字前缀

int i = 0b11111111;
Run Code Online (Sandbox Code Playgroud)

看到这里.

  • 这是一个扩展,可能需要一个特殊的标志让"gcc"理解它.当然不能移植到不支持该扩展的其他编译器. (12认同)

Avi*_*sov 7

使用BOOST_BINARY(是的,您可以在C中使用它).

#include <boost/utility/binary.hpp>
...
int bin = BOOST_BINARY(110101);
Run Code Online (Sandbox Code Playgroud)

在预处理期间,此宏将扩展为八进制文字.

  • 在大多数程序中混入像 boost 这样的巨大库并不是一个好主意。特别是如果它们做得很小并且编译速度很快。由于 C 已经通过扩展支持它,我建议任何人围绕它进行构建并使用版本宏进行切换。 (2认同)