我经常希望我能在c中做这样的事情:
val1 &= 0b00001111; //clear high nibble
val2 |= 0b01000000; //set bit 7
val3 &= ~0b00010000; //clear bit 5
拥有这种语法似乎是对C语言的一个非常有用的补充,我想不出它有什么缺点,而且对于一种低级语言来说,这似乎是一件很自然的事情,因为在这种语言中,位操作是相当常见的。
编辑:我看到了其他一些很好的替代方法,但当掩码更复杂时,它们都崩溃了。例如,如果reg
是控制微控制器上I/O引脚的寄存器,我想将引脚2、3我可以写reg = 0x46;
,但是我必须花10秒钟来思考它(在一两天不看这些代码之后,我每次阅读这些代码时可能都要花10秒钟)或者我可以写reg = (1 << 1) | (1 << 2) | (1 << 6);
,但我个人认为这比写'reg = 0b01000110要清楚得多;我同意它不能扩展到超过8位或者16位架构,但我从来没有需要做一个32位的掩码。
9条答案
按热度按时间bvjxkvbb1#
根据Rationale for International Standard - Programming Languages C §6.4.4.1 * 整型常量 *
由于缺乏先例和实用性不足,添加二进制常量的建议被拒绝。
它不在标准C中,但GCC支持它作为扩展,前缀为
0b
或0B
:详情请参见此处。
hk8txs482#
这就是为什么hexadecimal是...十六进制的原因。“... * 十六进制记数法的主要用途是在计算和数字电子产品中方便人们使用的二进制编码值的表示法... *"。它将如下所示:
十六进制:
1.一个十六进制数字可以代表一个半字节(4位或半个八进制)。
1.两个十六进制数字可以表示一个字节(8位)。
1.缩放到较大遮罩时,十六进制要紧凑得多。
经过一些练习,十六进制和二进制之间的转换会变得自然得多。试着用手写出你的转换结果,而不是使用在线的bin/hex符号转换器--那么几天后它就会变得自然(结果也会更快)。
**旁白:**尽管二进制常量不是C标准,但如果你用GCC编译,就可以使用二进制常量,它们应该以'0 b'或'0 B'为前缀。更多信息请参见官方文档here。例如:
eivgtgni3#
你所有的例子都可以写得更清楚:
(正如《自然》杂志所希望的那样,我冒昧地将评论修改为从零开始计数。)
你的编译器会折叠这些常量,所以这样写它们不会有性能损失,而且它们比
0b...
版本更容易阅读。mftmpeh84#
我认为可读性是最重要的,虽然是低级的,但是阅读和维护代码的是人,而不是机器。
您是否很容易发现您错误地键入了
0b1000000000000000000000000000000(0x40000000)
,而您真正的意思是0b10000000000000000000000000000000(0x80000000)
?ygya80vv5#
例如,如果reg是控制微控制器上I/O引脚的寄存器
我不禁认为这是一个糟糕的例子,控制寄存器中的位有特定的功能(任何连接到单个IO位的设备也是如此)。
在头文件中为位模式提供符号常量比在代码中计算二进制要明智得多。将二进制转换为十六进制或八进制很简单,记住将01000110写入IO寄存器时会发生什么就不简单了,特别是如果您手边没有数据手册或电路图。
这样,您不仅可以保存10秒钟的时间来计算二进制代码,而且还可以节省更长的时间来计算它的功能!
z3yyvxxp6#
我建议在C中使用C宏来避免编译器警告或其他问题。我使用Ox而不是0x(就像在“俄亥俄州”中一样)。
vi4fp9gy7#
我的方法是:
它会进行预处理...
wlp8pajw8#
在控制器上设置特定输出时,二进制是最有用的。我使用了一种技术上非法的方法,但总是有效。如果你只是需要打开一个LED,那么使用整个int,甚至是char来完成这项工作会冒犯你的每一种感觉。不要忘记,我们可能不是在讨论这些事情的最终编译复杂性。所以,对于与组控制相结合的个人可理解性,我使用位域:
当单独使用时,它们很容易被寻址,或者为了更彻底的控制,它们可以被视为一个无符号的int,公然无视K&R:-
它一直为我工作,它可能不是便携式的,但谁实际上端口这样的东西无论如何?给予它一个尝试。
j7dteeu89#
下面的代码被限制在8位,尽管它应该可以直接扩展。虽然它不会产生C文本,但它确实会产生编译时常量。
下面的函数编译为返回常量
18
的代码。在线试用!
如果性能不是问题,您可以做一些更简单的事情: