繁体   English   中英

将整数值作为二进制分配给 C 中的变量

[英]Assigning an integer value as binary to a variable in C

如何将像 111 这样的整数值分配给另一个整数值,但将 111 视为二进制?

例如我想这样做:

int x = 0b111; // x has the value 7

但我将“111”保存为整数;

我试图做的是这样的:

int value = 111;

int x = 0bvalue;

显然这是行不通的。 那我该怎么做呢?

一种方法是将值转换为字符串并转换回指定基数的整数。

int value = 111;

char buffer[1024];
snprintf(buffer, sizeof(buffer), "%d", value);

int x = strtol(buffer, NULL, 2);

另一种方法是转换整数而不转换为字符串。

int value = 111;

int x = 0;
for (int delta = 1, value2 = value; value2 > 0; value2 /= 10, delta *= 2) {
    x += (value2 % 10) * delta;
}

最好的解决方案是使用十六进制。 可以安全地假设任何阅读您代码的人都是程序员,因此知道十六进制。 然而,二进制是一种非常麻烦的格式,尤其是超过 8 位的格式,这就是标准不提供它的原因 - 0b是非标准的编译器扩展。

例如,当您看到为 32 位 MCU 编写的类似内容时,您就知道您正在与一个非常不称职的程序员打交道:

SPICR = 0b10001111001100101010111001001111; // see manual page 666

人们用更少的钱扔掉了他们的键盘。


如果出于某种原因仍然需要二进制编译时常量,则可以使用允许0b前缀的非标准编译器扩展或在标准 C 中编写宏。 后者可以按如下所述完成:

  • 给定一个预处理器标记,例如00001111 ,我们可以使用# "stringify" 运算符将其转换为预处理器中的字符串。 假设我们有一个像#define BIN(n) #n这样的宏。
  • 从那以后,我们最终得到一个字符串文字"00001111" ,我们可以像数组一样访问它。 所以(#n)[0]会给我们第一个'0'数字,现在是 ASCII 格式。
  • 这样我们就可以抓取每个单独的数字。 (#n)[0] - '0'将给出值 0 或 1 而不是 ASCII 字符串。
  • 如果我们根据字符串位置移动这个值,我们就会得到那个数字的二进制值。 例如((#n)[0] - '0') << 7给出值 128。
  • 如果我们对所有数字都这样做并对结果求和,我们就会得到值。

完整的宏可能如下所示:

#define TO_BIN(x) ((x)-'0')
#define BINARIFY(val, n) (TO_BIN(val) << n)
#define BIN8(n) ( \
  BINARIFY((#n)[0], 7) + \
  BINARIFY((#n)[1], 6) + \
  BINARIFY((#n)[2], 5) + \
  BINARIFY((#n)[3], 4) + \
  BINARIFY((#n)[4], 3) + \
  BINARIFY((#n)[5], 2) + \
  BINARIFY((#n)[6], 1) + \
  BINARIFY((#n)[7], 0) )

这可以变得更灵活,但现在让我们添加一些防御性编程以确保始终使用 8 位整数并且宏输入不是完全垃圾:

#define BIN(n) _Generic((n), int: sizeof(#n)==9 ? BIN8(#n) : 0 )

(仍然有一些方法可以欺骗该宏 - 它不是万无一失的,但总比没有好)

完整示例:

#include <stdio.h>

#define TO_BIN(x) ((x)-'0')
#define BINARIFY(val, n) (TO_BIN(val) << n)
#define BIN8(n) ( \
  BINARIFY(n[0], 7) + \
  BINARIFY(n[1], 6) + \
  BINARIFY(n[2], 5) + \
  BINARIFY(n[3], 4) + \
  BINARIFY(n[4], 3) + \
  BINARIFY(n[5], 2) + \
  BINARIFY(n[6], 1) + \
  BINARIFY(n[7], 0) )

#define BIN(n) _Generic((n), int: sizeof(#n)==9 ? BIN8(#n) : 0 )

int main (void)
{
    printf("%d\n", BIN(00001111)); //  15
    printf("%d\n", BIN(10000000)); // 128
    printf("%d\n", BIN(10101011)); // 171
}

请注意,这是纯实时的,二进制计算不消耗性能或内存,这与运行时发生的sprintfstrtoul调用不同。 例如 x86 程序集给出

    mov       esi, 15
    ...
    mov       esi, 128
    ...
    mov       esi, 171  

所以十进制值被硬编码到二进制中,就像我们使用二进制文字一样。 由于它是编译时计算,我们可以很好地获得只读常量:

const int x =  BIN(10101011);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM