我定义了两个变量:
uint8_t a[2];
uint16_t b;
接下来我想a
用作类型的变量uint16_t
,例如
b = (uint16_t)a;
但这是错误的!我的程序不适用于此类代码。当我替换b
为uint8_t b[2]
并使用元素操作时,一切正常。
为什么?
我定义了两个变量:
uint8_t a[2];
uint16_t b;
接下来我想a
用作类型的变量uint16_t
,例如
b = (uint16_t)a;
但这是错误的!我的程序不适用于此类代码。当我替换b
为uint8_t b[2]
并使用元素操作时,一切正常。
为什么?
a
是指向字节数组的指针。如果将其转换为 uint16_t 并将其分配给b
,b
则将包含 SRAM 中数组基址(存储位置)的地址。如果要将数组的两个字节a
视为整数,请按照 user14284 的建议使用联合,但请注意联合将代表体系结构的内存字节顺序中的字节数组(在 AVR 中会很少-endian,这意味着字节 0 是最低有效字节)。在代码中编写它的方法是:
union{
uint8_t a[2];
uint16_t b;
} x;
x.b[0] = 0x35;
x.b[1] = 0x4A;
// by virtue of the above two assignments
x.a == 0x4A35 // is true
不使用联合的另一种方法是a
强制转换为 uint16_t 指针,然后像这样取消引用它:
uint8_t a[2] = {0x35, 0x4A};
uint16_t b = *((uint16_t *) a);
b == 0x4A35; // because AVR is little endian
如果您使用缓冲区来存储大端数据(例如网络字节顺序),那么您需要进行字节交换才能使用这些技术中的任何一种。一种没有任何分支或临时变量的方法是:
uint8_t a[2] = {0x35, 0x4A};
a[0] ^= a[1];
a[1] ^= a[0];
a[0] ^= a[1];
a[0] == 0x4A; // true
a[1] == 0x35; // true
顺便说一句,这不是 AVR 甚至不是嵌入式问题。为 PC 编写的应用程序级网络代码通常调用称为htonl
, htons
(主机到网络,32 位和 16 位变体)和ntohl
, ntohs
(网络到主机,32 和 16 位变体)的函数,其实现取决于目标体系结构是否是否交换字节(假设“在线”传输的字节是多字节字的一部分时总是大端的)。
如果您的意图是将两个 8 位变量连接成一个 16 位变量,请使用union
. 如果要强制a
转换 into的单个成员b
,请指定要使用的数组的哪个元素。
在您的代码中,您只转换指向数组的指针。
您需要转换a
.
b = (uint16_t)*a;
我从未使用过 AVR,但如果您使用的是 16 位架构,则必须确保 a 是字对齐的。不这样做可能会导致异常。
a 的每个成员都是一个8 位数字。它不能容纳更大的东西。将其转换为 16 位不会对. 它只是提取a可能能够保存的任何值,并将其转换为 16 位,以便在值存储在那里时与b的格式匹配。
你甚至没有提到 a 的成员。您必须使用 a[0] 或 a[1](而不是 a[2]!)。如果你单独使用a,你只会得到它的地址。(很好,布鲁诺)。
将 a声明为两个 8 位数字的数组也不会使其成为 16 位数字。您可以使用 8 位序列以编程方式执行一些操作来存储和检索 16 位值,但不是您想的那样。