这里有几个问题在起作用。
首先,数组表达式可能不是赋值的目标。你不能写像
uint8_t original_dhost[6];
original_dhost = ethernet_hdr->ether_dhost;
因为表达式original_dhost
不是可修改的左值。这是有原因的,这将在下面变得显而易见。要将一个数组的内容复制到另一个数组,您需要单独复制每个元素,或者使用memcpy
库函数:
memcpy( original_dhost, ethernet_hdr->ether_dhost, sizeof original_dhost );
除非它是sizeof
或一元运算符的操作数&
,或者是用于在声明中初始化数组的字符串字面量,否则“N 元素数组T
”类型的表达式将被转换(“衰减”)为键入“pointer to T
”,表达式的值将是数组第一个元素的地址。结果不是可修改的左值;也就是说,它不能成为分配的目标。
在声明中
original_dhost = ethernet_hdr->ether_dhost;
表达式ethernet_hdr->ether_dhost
的类型为“6 元素数组uint8_t
”;因为它不是 thesizeof
或一元运算符的操作数&
,所以它被转换为类型为 "pointer to uint8_t
" 或的表达式uint8_t *
。此类型与 不兼容uint8_t [6]
,因此出现第一个错误。第二个错误是同样的问题,你只是颠倒了所涉及的玩家。
那么为什么不简单地将赋值的左侧也转换为指针并让赋值成功呢?是时候上一堂简短的历史课了。
C 派生自一种称为 B 的早期语言,它是一种“无类型”语言;所有数据都存储在固定大小的单词或“单元格”中,无论数据是否用于表示整数、实数值、文本等。记忆被视为细胞的线性阵列。当你在 B 中声明一个数组时,比如
auto arr[N];
编译器会留出 N+1 个单元格;数组的 N 个单元格,以及一个存储数组第一个元素的偏移量的附加单元格,它将绑定到符号arr
,如下所示:
+---+
arr: | | ---+
+---+ |
... |
+---+ |
arr[0]: | | <--+
+---+
arr[1]: | |
+---+
arr[2]: | |
+---+
...
+---+
arr[N-1]: | |
+---+
与在 C 中一样,下标操作arr[i]
计算为*(arr + i)
; 您将该值添加i
到存储在 中的偏移值arr
,然后取消引用结果。
Dennis Ritchie 在开发 C 时最初保留了 B 的数组语义,但是当他开始将struct
类型添加到语言中时遇到了问题。他希望结构内容直接映射到内存;他给出的一个例子是一个文件系统条目,比如
struct {
int inode;
char name[14];
};
他希望结构包含一个 2 字节整数值,紧跟一个以 0 结尾的字符串,但他不知道如何处理指向name
数组的指针:它应该作为结构的一部分存储,还是存储分别地?如果分开存放,应该存放 在哪里?
他通过完全摆脱数组指针解决了这个问题。他没有为指向数组第一个元素的指针留出存储空间,而是设计了这种语言,以便从数组表达式本身计算指针值。因此,在 C 中,当您声明一个数组时
T arr[N];
T
只分配了 N 个类型的元素:
+---+
arr[0]: | |
+---+
arr[1]: | |
+---+
arr[2]: | |
+---+
...
+---+
arr[N-1]: | |
+---+
没有单独的存储绑定到 symbol arr
。这就是为什么表达式&arr
和arr
都产生相同的值(数组中第一个元素的地址),即使两个表达式具有不同的类型(T (*)[N]
和T *
,分别)。这就是为什么数组表达式可能不是赋值的目标;没有什么可以给.