C语言 为什么 C 没有二进制文字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18244726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't C have binary literals?
提问by Drew
I am frequently wishing I could do something like this in c:
我经常希望我能在 c 中做这样的事情:
val1 &= 0b00001111; //clear high nibble
val2 |= 0b01000000; //set bit 7
val3 &= ~0b00010000; //clear bit 5
Having this syntax seems like an incredibly useful addition to C with no downsides that I can think of, and it seems like a natural thing for a low level language where bit-twiddling is fairly common.
拥有这种语法似乎是对 C 的一个非常有用的补充,没有我能想到的缺点,而且对于位处理相当普遍的低级语言来说,这似乎是一件很自然的事情。
Edit: I'm seeing some other great alternatives but they all fall apart when there is a more complex mask. For example, if regis a register that controls I/O pins on a microcontroller, and I want to set pins 2, 3, and 7 high at the same time I could write reg = 0x46;but I had to spend 10 seconds thinking about it (and I'll likely have to spend 10 seconds again every time I read those code after a not looking at it for a day or two) or I could write reg = (1 << 1) | (1 << 2) | (1 << 6);but personally I think that is way less clear than just writing `reg = 0b01000110;' I can agree that it doesn't scale well beyond 8 bit or maybe 16 bit architectures though. Not that I've ever needed to make a 32 bit mask.
编辑:我看到了其他一些不错的选择,但是当有更复杂的掩码时,它们都会分崩离析。例如,如果reg是一个控制微控制器上 I/O 引脚的寄存器,我想同时将引脚 2、3 和 7 设置为高电平,我可以写,reg = 0x46;但我不得不花 10 秒钟思考它(并且我'我可能要花 10 秒钟再读一遍这些代码,一两天不看它),或者我可以写,reg = (1 << 1) | (1 << 2) | (1 << 6);但我个人认为这比写“reg = 0b01000110;”要清晰得多。我同意它不能很好地扩展到 8 位或 16 位架构之外。并不是说我曾经需要制作 32 位掩码。
回答by Yu Hao
According to Rationale for International Standard - Programming Languages C§6.4.4.1 Integer constants
根据国际标准的基本原理 - 编程语言 C§6.4.4.1整数常量
A proposal to add binary constants was rejected due to lack of precedent and insufficient utility.
由于缺乏先例和实用性不足,添加二进制常量的提议被拒绝。
It's not in standard C, but GCC supports it as an extension, prefixed by 0bor 0B:
它不在标准 C 中,但 GCC 支持将其作为扩展名,以0bor为前缀0B:
i = 0b101010;
See herefor detail.
请参阅此处了解详细信息。
回答by Jacob Pollack
This is what pushed hexadecimalto be... hexadecimal. The "... primary use of hexadecimal notation is a human-friendly representation of binary-coded values in computing and digital electronics ...". It would be as follows:
这就是推动十六进制成为......十六进制的原因。“......十六进制表示法的主要用途是计算和数字电子学中二进制编码值的人性化表示......”。如下所示:
val1 |= 0xF;
val2 &= 0x40;
val3 |= ~0x10;
Hexadecimal:
十六进制:
- One hex digit can represent a nibble (4 bits or half an octal).
- Two hex digits can represent a byte (8 bits).
- Hex is much more compact when scaling to larger masks.
- 一个十六进制数字可以代表一个半字节(4 位或半个八进制)。
- 两个十六进制数字可以表示一个字节(8 位)。
- 当缩放到更大的掩码时,十六进制要紧凑得多。
With some practice, converting between hexadecimal and binary will become much more natural. Try writing out your conversions by hand and not using an online bin/hex notation converter -- then in a couple days it will become natural (and quicker as a result).
通过一些练习,十六进制和二进制之间的转换将变得更加自然。尝试手动写出您的转换,而不是使用在线 bin/hex 符号转换器 - 然后几天后它会变得自然(因此更快)。
Aside:Even though binary literals are not a C standard, if you compile with GCC it is possible to use binary literals, they should be prefixed with '0b' or '0B'. See the official documentation herefor further information. Example:
旁白:即使二进制文字不是 C 标准,如果您使用 GCC 进行编译,则可以使用二进制文字,它们应该以“0b”或“0B”为前缀。有关更多信息,请参阅此处的官方文档。例子:
int b1 = 0b1001; // => 9
int b2 = 0B1001; // => 9
回答by Nemo
All of your examples can be written even more clearly:
你所有的例子都可以写得更清楚:
val1 &= (1 << 4) - 1; //clear high nibble
val2 |= (1 << 6); //set bit 6
val3 &=~(1 << 3); //clear bit 3
(I have taken the liberty of fixing the comments to count from zero, like Nature intended.)
(我冒昧地将评论修正为从零开始计数,就像大自然所希望的那样。)
Your compiler will fold these constants, so there is no performance penalty to writing them this way. And these are easier to read than the 0b...versions.
您的编译器将折叠这些常量,因此以这种方式编写它们不会降低性能。这些比0b...版本更容易阅读。
回答by Eric Z
I think readability is a primary concern. Although low-level, it's human beings who read and maintain your code, not machine.
我认为可读性是首要考虑的问题。尽管是低级的,但阅读和维护您的代码的是人,而不是机器。
Is it easy for you to figure out that you mistakenly typed 0b1000000000000000000000000000000(0x40000000), where you really mean 0b10000000000000000000000000000000(0x80000000)?
您是否很容易发现您打错了字0b1000000000000000000000000000000(0x40000000),而您真正的意思是0b10000000000000000000000000000000(0x80000000)?
回答by Simon
"For example, if reg is a register that controls I/O pins on a microcontroller"
“例如,如果 reg 是控制微控制器上 I/O 引脚的寄存器”
I can't help thinking this is a bad example. Bits in control registers have specific functions (as will any devices connected to individual IO bits).
我不禁认为这是一个不好的例子。控制寄存器中的位具有特定功能(与连接到各个 IO 位的任何设备一样)。
It would be far more sensible to provide symbolic constants for bit patterns in a header file, rather than working out the binary within the code. Converting binary to hexadecimal or octal is trivial, remembering what happens when you write 01000110 to an IO register is not, particularly if you don't have the datasheet or circuit diagram handy.
在头文件中为位模式提供符号常量会更明智,而不是在代码中计算二进制。将二进制转换为十六进制或八进制是微不足道的,记住将 01000110 写入 IO 寄存器时会发生什么,尤其是当您手头没有数据表或电路图时。
You will then not only save those 10 seconds trying to work out the binary code, but maybe the somewhat longer time trying to work out what it does!
然后,您不仅可以节省 10 秒尝试计算二进制代码的时间,而且可能会节省一些更长的时间来尝试计算它的作用!
回答by Lonesome Twin
Binary is most useful when setting specific outputs on a controller. I use a hack which is technically illegal but nonetheless always works. If you just need to turn an LED on it offends every sensibility to use a whole int, or even a char for the job. Don't forget we're probably not talking about the ultimate in compilation sophistication for these things. So, for individual intelligibility combined with group control I use bitfields :-
在控制器上设置特定输出时,二进制最有用。我使用了一种技术上非法但仍然有效的黑客。如果您只需要打开一个 LED,它就会冒犯使用整个 int 甚至是 char 来完成工作的所有敏感性。不要忘记,我们可能不是在谈论这些东西的终极编译复杂度。因此,对于结合组控制的个人可理解性,我使用位域:-
struct DEMAND
{
unsigned int dOil : 1; // oil on
unsigned int dAir : 1; // air on
unsigned int dHeat : 1; // heater on
unsigned int dMtr1 : 1; // motor 1 on
unsigned int dMtr2 : 1; // motor 2 on
unsigned int dPad1 : 10;// spare demand o/p's
unsigned int dRunCycle: 1; // GO !!!!
unsigned int dPad2 : 15;// spare o/p's
unsigned int dPowerOn: 1; // Power on
}DemandBF;
They're easily addressed when used singly, or for more thorough control they can be treated as an unsigned int in flagrant disregard of K&R:-
它们在单独使用时很容易解决,或者为了更彻底的控制,它们可以被视为 unsigned int 公然无视 K&R:-
void *bitfPt = &DemandBF;
unsigned int *GroupOuts = (unsigned int *)bitfPt;
DemandBF.dAir = 1; // Clearly describes what's turning on
DemandBF.dPowerOn = 1;
*GroupOuts ^= 0x04; // toggle the heater
*GroupOuts = 0; // kill it all
It's always worked for me, it's probably not portable, but then who actually ports something like this anyhow? Give it a go.
它总是对我有用,它可能不便携,但是无论如何谁实际上移植了这样的东西?搏一搏。
回答by jxh
The following is limited to 8 bits, although it should be straightforward to extend. While it does not result in a C literal, it does result in a compile time constant.
以下内容仅限于 8 位,但扩展起来应该很简单。虽然它不会产生 C 文字,但会产生编译时常量。
#define B_(X) B8_("00000000" #X)
#define B8_(X) B8__(X+sizeof(X)-9)
#define B8__(X) \
(B___((X), 7) | B___((X), 6) | B___((X), 5) | B___((X), 4) | \
B___((X), 3) | B___((X), 2) | B___((X), 1) | B___((X), 0))
#define B___(X, I) (((X)[7-(I)] - '0') << (I))
The following function is compiled into code that returns the constant 18.
以下函数被编译成返回常量的代码18。
int test(void) {
return B_(10010);
}
If performance is not an issue, you can do something simpler:
如果性能不是问题,您可以做一些更简单的事情:
#define B_(x) strtoull(#x, 0, 2)

