嵌入式C语言:var = 0xFF;是什么意思?

19

我第一次使用嵌入式C进行开发。虽然我的C语言有点生疏,但我能读懂代码,但我不太了解某些行为的原因。例如,我想知道一个变量是否为真或假,并将其传回另一个应用程序。原始实现者选择将变量设置为0xFF,而不是设置为1或0。

他是试图将它设置为地址空间吗?还是其他原因导致布尔变量被设置为255?

9个回答

31

0xFF设置char中的所有位。

最初的实现者可能认为标准的01不够好,决定如果所有位都是off,则为false,但如果所有位都是on,则为true

这个方法有效是因为在C语言中,除了0之外的任何值都是true。尽管这将设置char中的所有字节,但对于任何其他变量类型,只要变量中有一个位被设置为1,它就会返回true。


5
0xFF 将 char 类型的所有位都设为1。对于整数类型而言,其效果受到具体实现、数据大小和符号属性的影响。 - Steve Fallows
3
顺便提一下,这也是为什么VB在表示真值时使用-1,而在表示假值时使用0的原因。-1在二进制补码中全部都是1。 - Kibbee
@Steve:即使对于char类型,它也取决于实现(例如,如果CHAR_BIT != 8)。 - Alexandre C.
“可能决定...不够好”听起来像是瞎猜。 - Olof Forshell

12

如果你急需内存,你可能想要在一个字节中存储8个布尔值(或在long中存储32个,或其他什么)

这可以通过使用标志掩码轻松实现:

  // FLAGMASK = ..1<<n for n in 0..7...
  FLAGMASK = 0x10;    // e.g. n=4

  flags &= ~FLAGMASK; // clear bit
  flags |= FLAGMASK;  // set bit
  flags ^= FLAGMASK;  // flip bit
  flags = (flags & ~FLAGMASK) | (booleanFunction() & FLAGMASK); // clear, then maybe set

只有当booleanFunction()返回0(所有位都清除)或-1(所有位都设置)时,此代码才有效。


5
这是对原问题的回答吗? - Olof Forshell

9

0xFF是~0的十六进制表示(即11111111)

例如,在VB和Access中,-1被用作True。


9
这些年轻人,他们知道什么?
在最初的嵌入式语言之一 - PL/M (-51,如8051、-85、-86、-286、-386) - 逻辑运算符(!, &&, || 在C中) 和位运算符(~, &, |, ^) 之间没有区别。相反,PL/M 使用 NOT、AND、OR 和 XOR 来处理两种类型。我们采用两种类别是否更好?我不太确定。虽然我想念 C 中的逻辑 ^^ 运算符(xor),但我认为可能会构建 C 程序而不必涉及逻辑类别。
在 PL/M 中,False 被定义为 0。布尔值通常表示为字节变量。True 被定义为 NOT False,这将给出 0ffh(PL/M-ese 对应 C 的 0xff)。
为了看到状态标志进位转换为存储在字节(布尔型不可用作类型)变量中之前的情况,PL/M 可以在存储之前使用汇编指令 "sbb al,al"。如果设置了进位,则 al 将包含 0ff,如果没有,则将包含 0h。如果需要相反的值,则 PL/M 将在 sbb 之前插入 "cmc",或者在之后附加 "not al"(实际上是 xor - 其中之一)。
因此,TRUE 的 0xff 是从 PL/M 直接兼容移植而来。必要吗?可能不是,除非你对自己的技能(在 C 中)不确定并且采取超级安全措施。
正如我所想的那样。
PL/M-80(用于 8080、8085 和 Z80)不支持整数或浮点数,我怀疑 PL/M-51 也是如此。PL/M-86(用于 8086、8088、80188 和 80186)添加了整数、单精度浮点数、段:偏移指针和标准内存模型 small、medium、compact 和 large。对于那些倾向于这样做的人,有特殊的指令来创建自制混合内存模型。Microsoft 的 huge 内存模型相当于 intel 的 large。MS 还拥有 tiny、small、compact、medium 和 large 模型。

4

在嵌入式系统中,通常只有一个程序员编写所有代码,他/她的个人习惯贯穿整个源代码。许多嵌入式程序员是硬件工程师,必须尽力使系统运行良好。没有“可移植性”的要求或概念。另一个考虑因素是嵌入式系统的编译器是特定于CPU硬件的。请参考该CPU的ISA,并检查所有使用“boolean”的情况。


3

正如其他人所说,它将所有位设置为1。由于这是嵌入式C语言,您可能会将其存储到每个位对某些重要内容都很重要的寄存器中,因此您想将它们全部设置为1。我知道当我使用汇编语言编写时也会做类似的事情。


1
这是对原问题的回答吗? - Olof Forshell
是的。你错过了我回答作业的功能以及为什么要这样做的一个原因的部分了吗? - Paul Tomblin
问题是为什么有人在C语言中使用0xff而不是0x01来表示TRUE。问题并不是为什么有人将字节中的八个位用作八个单独的T/F字段。 - Olof Forshell
1
与您完整的PL/M历史相反,您真的认为PL/M在这里是相关的吗?也许与其抨击其他人的答案,您可以致力于改进自己的答案。您可以从删除三分之四的离题和无聊内容开始。 - Paul Tomblin
8051于1980年推出,PL/M于1972年推出。唯一的语言选择是汇编语言,因此决策者们很理性地使用PL/M,除非绝对必要才使用汇编语言。需要明确的是:PL/M是8051唯一使用0xff表示TRUE的语言。当英特尔停止支持它时,新的高级开发语言选择是C语言。最快的移植方式是使用现有的PL/M逻辑,包括0xff表示TRUE。你对一个没有被问到的问题的“回答”更有说服力吗?是的,历史很无聊,但了解它可以真正避免猜测。 - Olof Forshell

3

关于这个问题,真正需要知道的是“var”的类型。你说“boolean”,但它是C++/C99的布尔类型,还是(很可能是一个嵌入式C应用程序),完全不同类型的东西被用作布尔值?


最佳答案请除去无根据的猜测以外。 - Olof Forshell

2
此外,将1加到0xff会将其设置为0(假设为无符号字符),检查可能已经在循环中进行,并且增量用于跳出循环。

1
这里有一个可能的原因:0xff0的二进制补码。在您的嵌入式架构上,将0xff存储到变量中可能比存储1更有效,因为后者可能需要额外的指令或存储在内存中的常量。
或者,在您的架构中,检查寄存器的“真值”最有效的方法是使用“检查位设置”指令。以0xff作为TRUE值,无论检查哪个位...它们都被设置了。
当然,上述只是猜测,没有知道您使用的嵌入式处理器类型。8位、16位、32位?PIC、AVR、ARM、x86?
(正如其他人指出的那样,在C语言中,除零以外的任何整数值都被视为布尔表达式的TRUE。)

嗯,在8051指令集中,没有任何东西可以使将寄存器设置为0xFF比设置为1更容易。我很困惑,也许这只是这个特定编码者的习惯,也许这是一种未记录的黑客技巧,用于其他地方使用的位操作技巧...? - Dan Lenski
我倾向于相信是程序员的问题而不是硬件的问题。我发现这是他的第一个嵌入式系统,他因不良工作而被解雇。 - Dan
可能的原因?几乎不可能。看看我的答案。 - Olof Forshell

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