Arduino 左移无法按预期工作,编译器错误? [英] Arduino left shift not working as expected, compiler bug?

查看:38
本文介绍了Arduino 左移无法按预期工作,编译器错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

uint32_t a = 0xFF << 8;
uint32_t b = 0xFF;
uint32_t c = b << 8;

我正在为 Uno(1.0.x 和 1.5)编译,很明显 ac 应该是相同的值,但它们不是...至少在目标上运行时不会.我在主机上编译了相同的代码,没有问题.

I'm compiling for the Uno (1.0.x and 1.5) and it would seem obvious that a and c should be the same value, but they are not... at least not when running on the target. I compile the same code on the host and have no issues.

右移工作正常,左移仅在我移动变量而不是常量时有效.

Right shift works fine, left shift only works when I'm shifting a variable versus a constant.

谁能确认一下?

我在 VS2013 中使用 Visual Micro.使用 1.0.x 或 1.5 Arduino 编译会导致相同的失败.

I'm using Visual Micro with VS2013. Compiling with either 1.0.x or 1.5 Arduino results in the same failure.

在目标上:

A = 0xFFFFFF00
C = 0x0000FF00

推荐答案

问题与有符号/无符号隐式转换有关.

The problem is related to the signed/unsigned implicit cast.

随着 uint32_t a = 0xFF <<<8;你的意思是

  • 0xFF 已声明;它是一个 signed char;
  • 有一个 <<操作,以便将变量转换为 int.因为它是一个有符号的字符(所以它的值是 -1),所以用 1 填充,以保留符号.所以变量是0xFFFFFFFF;
  • 它被移位了,所以 a = 0xFFFFFF00.
  • 0xFF is declared; it is a signed char;
  • There is a << operation, so that variable is converted to int. Since it was a signed char (and so its value was -1) it is padded with 1, to preserve the sign. So the variable is 0xFFFFFFFF;
  • it is shifted, so a = 0xFFFFFF00.

注意:这有点错误,请参阅下面的更正确"版本

NOTE: this is slightly wrong, see below for the "more correct" version

如果您想重现相同的行为,请尝试以下代码:

If you want to reproduce the same behaviour, try this code:

uint32_t a = 0xFF << 8;
uint32_t b = (signed char)0xFF;
uint32_t c = b << 8;

Serial.println(a, HEX);
Serial.println(b, HEX);
Serial.println(c, HEX);

结果是

FFFFFF00
FFFFFFFF
FFFFFF00

或者,换句话说,如果你写

Or, in the other way, if you write

uint32_t a = (unsigned)0xFF << 8;

你知道 a = 0x0000FF00.

编译器有两个奇怪的地方:

There are just two weird things with the compiler:

  1. uint32_t a = (unsigned char)0xFF <<8; 返回 a = 0xFFFFFF00
  2. uint32_t a = 0x000000FF <<<8; 也返回 a = 0xFFFFFF00.
  1. uint32_t a = (unsigned char)0xFF << 8; returns a = 0xFFFFFF00
  2. uint32_t a = 0x000000FF << 8; returns a = 0xFFFFFF00 too.

也许这是编译器中的错误转换....

Maybe it's a wrong cast in the compiler....

正如phuclv所指出的,上面的解释略有错误.正确的解释是,uint32_t a = 0xFF <<8;,编译器做这个操作:

As phuclv pointed out, the above explanation is slightly wrong. The correct explanation is that, with uint32_t a = 0xFF << 8;, the compiler does this operations:

  • 0xFF 已声明;它是一个 int;
  • 有一个 <<操作,因此这变成 0xFF00;它是一个整数,所以它是负的
  • 然后将其提升为 uint32_t.由于它是负数,1s 被前置,导致 0xFFFFFF00
  • 0xFF is declared; it is an int;
  • There is a << operation, and thus this becomes 0xFF00; it was an int, so it is negative
  • it is then promoted to uint32_t. Since it was negative, 1s are prepended, resulting in a 0xFFFFFF00

与上面的解释不同的是,如果你写uint32_t a = 0xFF <<7; 你得到 0x7F80 而不是 0xFFFFFF80.

The difference with the above explanation is that if you write uint32_t a = 0xFF << 7; you get 0x7F80 rather than 0xFFFFFF80.

这也解释了我在上一个答案末尾写的两个奇怪"的东西.

This also explains the two "weird" things I wrote in the end of the previous answer.

参考,在评论中链接的线程 还有一些关于编译器如何解释文字的解释.特别是在 this answer 中有一个表格,其中包含编译器分配给文字的类型.在这种情况下(无后缀,十六进制值),编译器根据适合该值的最小类型分配此类型:

For reference, in the thread linked in the comment there are some more explanations on how the compiler interpretes literals. Particularly in this answer there is a table with the types the compiler assigns to the literals. In this case (no suffix, hexadecimal value) the compiler assigns this type, according to what is the smallest type that fits the value:

  1. int
  2. unsigned int
  3. long int
  4. unsigned long int
  5. long long int
  6. unsigned long long int

这导致了一些更多的考虑:

This leads to some more considerations:

  • uint32_t a = 0x7FFF <<8; 这意味着文字被解释为有符号整数;提升到更大的整数扩展了符号,所以结果是 0xFFFFFF00
  • uint32_t b = 0xFFFF <<<8; 这种情况下的文字被解释为一个无符号整数.因此提升为 32 位整数的结果是 0x0000FF00
  • uint32_t a = 0x7FFF << 8; this means that the literal is interpreted as a signed integer; the promotion to the bigger integer extends the sign, and so the result is 0xFFFFFF00
  • uint32_t b = 0xFFFF << 8; the literal in this case is interpreted as an unsigned integer. The result of the promotion to the 32-bit integer is therefore 0x0000FF00

这篇关于Arduino 左移无法按预期工作,编译器错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆