0

我正在尝试交换结构中的两个条目。

这是结构:

struct hdr {
    uint8_t ether_dhost[6];
    uint8_t ether_shost[6]; 
}

当我尝试将这些值保存在临时数组中时,我在此行收到此错误:

uint8_t original_dhost[6];
original_dhost = ethernet_hdr->ether_dhost;

'uint8_t[6]'从类型'uint8_t *'分配给类型时不兼容的类型

所以我尝试使用指针而不是数组:

uint8_t *original_dhost;

然后我没有收到错误,但是当我尝试分配给 时ethernet_hdr->ether_dhost,我收到了这个错误:

ethernet_hdr->ether_shost = original_dhost;
incompatible types when assigning to type ‘uint8_t[6]’ from type ‘uint8_t *’

我怎样才能避免上面的第一个错误?具体来说,为什么编译器说该字段是'uint8_t *'当我将其声明为数组时?

4

6 回答 6

4

ether_dhost是一个数组。您不能使用简单的赋值语句复制到它或从它复制。

您的第一个错误是因为ethernet_hdr->ether_dhost解析为第一个元素(uint8_t指针)的地址,但您不能将其值分配给新数组。

您需要使用 memcpy (或循环)来复制所有元素:

uint8_t original_dhost[6];
memcpy(original_dhost,ethernet_hdr->ether_dhost,sizeof(original_dhost));
于 2013-10-03T16:10:06.563 回答
3

这里有几个问题在起作用。

首先,数组表达式可能不是赋值的目标。你不能写像

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。这就是为什么表达式&arrarr都产生相同的(数组中第一个元素的地址),即使两个表达式具有不同的类型T (*)[N]T *,分别)。这就是为什么数组表达式可能不是赋值的目标;没有什么可以.

于 2013-10-03T18:48:04.793 回答
0

没有特别的原因(除了一些历史事故),在 C 中你不能直接分配数组;您必须一个一个地复制元素(或使用 memcpy)。

memcpy(ethernet_hdr->ether_shost,original_dhost,sizeof(original_dhost));
于 2013-10-03T16:11:27.797 回答
0

数组是指向固定数量的连续对象的指针。因此,要实现您想要的移动,请使用memcpy

于 2013-10-03T16:11:54.600 回答
0

struct entry声明了一个数组类型的字段,但是编译器说它是一个指针

因为数组在被引用时几乎总是衰减(隐式转换)为指针。

当我尝试分配给 ethernet_hdr->ether_dhost 时,我收到此错误:

当然。数组不是可修改的左值;如果你想“分配”它们,你不能直接这样做。改为使用memcpy()

于 2013-10-03T16:12:32.777 回答
0
于 2013-10-03T17:07:23.513 回答