按位或运算符用于将整数和字符进行按位或操作。

3

我有一个值,我知道它小于16(不超过4个比特)在一个int中。我想将其按位或到一个char中。我可以这样做吗:

c |= i;

这是否取决于字节顺序(endianness)?如果是问题,那么这样做是否可行:

c |= (char)i;

解决它?


1
建议:选择一种语言并坚持使用它。不要尝试编写多语言源文件:这是非常艰苦的工作 :) - pmg
1
@pmg 在这种情况下,C和C++都是相关的,并且有相同的答案。 - James Kanze
@pmg 我正在写C++,但由于这个领域对于C来说是相同的,所以我也包括了它。 - Baruch
经验法则:在99%的情况下,当您发现自己在有符号整数类型上进行位运算时,这意味着您很困惑并且不知道自己在做什么。如果您在char上进行位运算,情况就更加如此,因为char可以是有符号或无符号的,它是实现定义行为。 - Lundin
@Lundin 因为我只使用char的位值,从未使用过它的整数值(也没有左移操作),所以无论它是有符号还是无符号都没有影响。 - Baruch
4个回答

9

在进行算术运算时,字节序并不重要,只有在以某种其他方式处理值(大于1个char)时才重要,例如使用char指针遍历保存较大值的缓冲区。

在您的情况下,没有必要进行强制类型转换,自动算术提升会确保一切正常。代码如下:

char c = 0;
int  i =3;

c |= i;

等同于

c = c | i;

表达式将会被计算为int类型,然后再转换回存储类型。

感谢@unwind。我一直在苦恼如何解释这个问题,还有那些独角兽。 - Elazar
我认为在他的问题中,cchar,而iint - James Kanze
现在解释一下当其中一个整数具有负值时会发生什么(考虑“符号+大小”与“2的补码”以及实现可能定义的其他内容)。 :-) - Brendan
@unwind 我也见过它有影响,但只有一两次。但通常出现在系统级代码中(例如,在C标准库中实现的modf函数中,我必须从double中提取指数)。这通常不是问题。 - James Kanze
@unwind 如果你真的想要详细说明:c |= i; 相当于 c = static_cast<char>( static_cast<int>( c ) | i );。至少在概念上,编译器会将 char 转换为 int 进行 | 操作,然后将结果转换回 char。(当然,在可以对 char 进行硬件或操作的机器上(大多数机器都不能这么做),编译器很可能会意识到所有这些类型转换对结果没有影响,并放弃它们。) - James Kanze
显示剩余2条评论

3

这与字节序无关。 c |= i; 将直接起作用。


@DanielFischer 我很确定这要么是魔法,要么是独角兽,或者两者都有! - JustSid
@JamesKanze 我认为它可能不会的原因是如果 char 与 LSB 进行了 OR 操作。但是现在我写这篇文章时,我不确定为什么我曾经会这样想。 - Baruch
LSB/MSb 的定义不受字节序影响。 - Elazar
1
实际上,char 将与 LSB 进行或运算。无论该字节在 int 的内存布局中的位置如何。 - James Kanze
@Elazar 在我的评论中,我指的是第一个字节,而不是实际的最低有效位。正如我所写的,我越来越不确定当时在我脑海中想的是什么。 - Baruch
显示剩余2条评论

1
我更喜欢像这样做,如果目标比源更宽(有更多位),则可以防止符号扩展:c = c | (0x0f & i); 这也作为提醒,指出源中哪些位是要提取的目标位。

1
看到 OP 想要四个位,那不应该是 c = c | (0x0f & i); 吗? - pmg
1
最佳实践是永远不要对有符号数进行位运算。在这种特定情况下,这并不是一个问题。但由于您提到了符号扩展,编写此表达式的最安全方式是 c = c | (0x0fu & i);,因为它将强制 C 的隐式类型提升规则确保结果为无符号数(然后截断为 char)。 - Lundin
在使用掩码时,我认为不需要使用无符号说明符'u'。 - Dave
1
u将把字面量0x0f转换为unsigned int类型。这将进而将操作0x0fu & i的结果转换为无符号整数。这将进而将c | (0x0fu & i)的结果转换为无符号整数。如果您不知道C中隐式类型提升的工作原理,那么永远不要考虑对有符号整数类型进行位运算。您将会产生大量非常微妙的错误。 - Lundin
1
@Lundin 最佳实践是不要在有符号类型上执行位运算。而且 ci 应该是 unsigned charunsigned int。但由于他明确表示只使用了四个低位,所以这没关系。 - James Kanze
显示剩余2条评论

-3

你最好使用 c |= (char)(i);


2
为什么? 对我来说,这似乎只是多余的噪音。(例如,他可能希望在c |= i;之前加上一个断言:assert((i&〜0x0F)== 0);。但那是另外一个问题。) - James Kanze
我在大端和小端机器上都尝试了,结果是一样的。所以,实际上并不重要。我更喜欢使用类型转换,这样可以提醒自己我知道我正在混合两种类型。 - unxnut
这个强制类型转换只能说明你不知道C语言中隐式类型提升的工作原理。这个转换是多余的垃圾,没有任何作用。打印 sizeof(c | (char)some_int),它将是一个整数的大小。如果你想要一个类型转换来提醒自己某些事情,你应该写成 c = (char)(c | i);,这至少是有意义的。 - Lundin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接