【问题标题】:Writing binary number system in C code [duplicate]用C代码编写二进制数系统[重复]
【发布时间】:2013-02-13 09:08:42
【问题描述】:

当我们使用0x 前缀表示十六进制数,使用0 表示八进制数时,有什么可以对二进制数做的吗?

我尝试了b 后缀,但GCC 不允许。

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

有可能吗?

【问题讨论】:

  • C 中不存在二进制文字。最接近的是十六进制,因为它们紧密遵循二进制位模式。
  • 十六进制转二进制真的很容易。

标签: c


【解决方案1】:

标准 C 没有定义二进制常量。不过有一个 GNU C 扩展(在流行的编译器中,clang 也适应它):0b0B 前缀:

int foo = 0b1010;

如果你想坚持使用标准 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;
}

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

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。整洁吧?

【讨论】:

  • @Lundin 嗯?重点是可读性和具有二进制文字
  • @Lundin 我反对吗? OP问“这怎么可能”,我已经向他展示了如何。是时候让我一个人呆着了。
  • “重点是可读性...”确实是支持二进制文字的论据。
  • @Lundin 在很多情况下,很多人会发现二进制数更具可读性。事实上,在定义带有大量标志的枚举时,许多程序员会在注释中使用其二进制值来注释每个常量。事实上,现在 C++ 提供了用户定义的文字,许多人实现的第一个是二进制数字文字的扩展。
  • @Lundin - 从使用过大量嵌入式硬件的人那里得到它:我们经常不得不处理不以 CPU 数据中的低位开头的二进制值巴士有关。当然,在这种情况下,为您取值并对其进行移位的宏非常有用,并且可以处理可读性问题,有时能够简单地指定二进制文字会很好。我发现随着我越来越习惯于嵌入式编程,我对二进制文字的“需求”已经下降到几乎为零,但一开始它们似乎会很方便。
【解决方案2】:

使用0b 为您的文字添加前缀

int i = 0b11111111;

here

【讨论】:

  • 虽然它是一个扩展,但可能需要一个特殊的标志来让gcc 理解它。当然不能移植到不支持该扩展的其他编译器。
【解决方案3】:

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

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

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

【讨论】:

  • 当我使用带有变量的 BOOST_BINARY 时出现错误:#include #include int main() { int bin; printf("请输入你的二进制数:"); scanf("%i", &bin); printf("十进制值为%d", BOOST_BINARY(bin));返回0;错误说错误:宏“BOOST_DETAIL_SPLIT_AND_SWAP_PARAMS”需要2个参数,但只有1个给定
  • 在大多数程序中混入像 boost 这样的庞大库并不是一个好主意。特别是如果它们被制作得小而快速编译。由于 C 已经通过扩展支持它,我建议任何人围绕它构建并使用版本宏进行切换。
猜你喜欢
  • 2015-06-26
  • 1970-01-01
  • 2011-12-08
  • 2017-02-28
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 1970-01-01
  • 2011-07-23
相关资源
最近更新 更多