为什么C不具有二进制文字?

我经常希望我能在c中做这样的事情:

val1 &= 0b00001111; //clear high nibble val2 |= 0b01000000; //set bit 7 val3 &= ~0b00010000; //clear bit 5 

拥有这种语法似乎是C的一个非常有用的补充,没有我能想到的缺点,对于低级语言而言,这似乎是很自然的事情。

编辑:我看到了其他一些很好的选择,但是当有更复杂的面具时,它们都会崩溃。 例如,如果reg是控制微控制器上I / O引脚的寄存器,并且我想将引脚2,3和7设置为高电平,同时我可以写入reg = 0x46; 但是我不得不花10秒时间思考它(而且每次我在没有看一两天后阅读这些代码时我可能不得不再花10秒钟)或者我可以写reg = (1 << 1) | (1 << 2) | (1 << 6); reg = (1 << 1) | (1 << 2) | (1 << 6); 但我个人认为这不仅仅是写’reg = 0b01000110;’。 我同意它不会超出8位或16位架构。 不是说我曾经需要制作32位掩码。

根据国际标准的基本原理 – 编程语言 C§6.4.4.1 整数常数

添加二进制常量的提议由于缺乏先例和实用程序不足而被拒绝。

它不是标准的C,但是GCC支持它作为扩展,以0b0B为前缀:

  i = 0b101010; 

详情请见此处 。

这就是将hex推送到hex的内容。 “… hex表示法的主要用途是计算和数字电子设备中二进制编码值的人性友好表示…… ”。 它将如下:

 val1 |= 0xF; val2 &= 0x40; val3 |= ~0x10; 

hex:

  1. 一个hex数字可以表示半字节(4位或半个八进制)。
  2. 两个hex数字可以表示一个字节(8位)。
  3. 当缩放到更大的掩模时,Hex更紧凑。

通过一些练习,hex和二进制之间的转换将变得更加自然。 尝试手动写出你的转换,而不是使用在线bin / hex符号转换器 – 然后在几天内它将变得自然(并且因此更快)。

旁白:尽管二进制文字不是C标准,但如果使用GCC进行编译,则可以使用二进制文字,它们应该以“0b”或“0B”作为前缀。 有关详细信息,请参阅此处的官方文档。 例:

 int b1 = 0b1001; // => 9 int b2 = 0B1001; // => 9 

您可以更清楚地编写所有示例:

 val1 &= (1 << 4) - 1; //clear high nibble val2 |= (1 << 6); //set bit 6 val3 &=~(1 << 3); //clear bit 3 

(我已经冒昧地将评论从零开始计算,就像大自然一样。)

您的编译器将折叠这些常量,因此以这种方式编写它们不会有性能损失。 这些比0b...版本更容易阅读。

我认为可读性是一个主要问题。 虽然是低级别的,但是人类会阅读和维护您的代码,而不是机器。

您是否容易弄清楚您错误地键入了0b1000000000000000000000000000000(0x40000000) ,其中您的意思是0b10000000000000000000000000000000(0x80000000)

“例如,如果reg是一个控制微控制器上I / O引脚的寄存器”

我不禁想到这是一个糟糕的例子。 控制寄存器中的位具有特定function(连接到各个IO位的任何器件也是如此)。

为头文件中的位模式提供符号常量更为明智,而不是在代码中计算二进制文件。 将二进制转换为hex或八进制是微不足道的,记住将01000110写入IO寄存器时会发生什么,特别是如果您没有方便的数据表或电路图。

然后,您不仅可以节省10秒钟来计算二进制代码,还可能需要更长的时间来计算它的function!

如果您不需要实际的文字,您可以这样做:

 #define B_(x) strtoull(#x, 0, 2) unsigned char low_nibble = B_(00001111); unsigned char bit_7 = B_(01000000); unsigned char bit_5 = B_(00010000); val1 |= low_nibble; val2 &= bit_7; val3 |= ~bit_5; 

如果您坚持编译时常量,则以下内容不一般,但适用于8位。

 #define B0_(X) ((X) % 8 + B1_((X)/8) * 2) #define B1_(X) ((X) % 8 + B2_((X)/8) * 2) #define B2_(X) ((X) % 8 + B3_((X)/8) * 2) #define B3_(X) ((X) % 8 + B4_((X)/8) * 2) #define B4_(X) ((X) % 8 + B5_((X)/8) * 2) #define B5_(X) ((X) % 8 + B6_((X)/8) * 2) #define B6_(X) ((X) % 8 + B7_((X)/8) * 2) #define B7_(X) ((X) % 8) #define B_(x) B0_(0##x)