【问题标题】:Am I violating strict aliasing rules by creating dummy struct data types?我是否通过创建虚拟结构数据类型违反了严格的别名规则?
【发布时间】:2018-04-08 19:51:04
【问题描述】:

我有这两个功能:

static inline void *ether_payload(void *pkt)
{
  return ((char*)pkt) + 14;
}
static inline uint16_t ip_id(const void *pkt)
{
  const char *cpkt = pkt;
  uint16_t id;
  memcpy(&id, &cpkt[4], sizeof(id));
  return ntohs(id);
}

现在,存在类型安全问题。对于第一个函数,void 指针表示以太网头。对于第二个函数,void 指针表示 IPv4 标头。这产生了很大的可能性,即有人不小心直接调用了以太网标头的第二个函数。如果有人这样做,编译器不会给出警告。

我想通过两个从未定义其内容的虚拟结构来消除这种类型安全问题:

struct etherhdr;
struct ipv4hdr;

现在的功能是:

static inline struct ipv4hdr *ether_payload(struct etherhdr *pkt)
{
  return (struct ipv4hdr*)(((char*)pkt) + 14);
}
static inline uint16_t ip_id(const struct ipv4hdr *pkt)
{
  const char *cpkt = (const char*)pkt;
  uint16_t id;
  memcpy(&id, &cpkt[4], sizeof(id));
  return ntohs(id);
}

这解决了类型安全问题。请注意,我实际上并没有通过结构访问以太网或 IP 标头,这确实是非常糟糕的做法。

我的问题是,我定义这样的 API 是否违反了严格的别名规则?请注意,数据永远不会通过结构访问;只需使用 char 指针通过 memcpy 访问数据。我的理解是 char 指针可以是任何东西的别名。

让我们把以太网数据包可以包含 IPv6 的事实作为无关紧要的事实,因为这只是一个非常简单的示例。

【问题讨论】:

  • char* 确实允许别名。我在这里没有看到任何严格的别名违规。

标签: c strict-aliasing


【解决方案1】:

至于回答你的问题,Cornstalks 已经回答了,不,你没有违反任何严格的别名规则。
您可以将指针转换为 char 指针。如果您确定另一个指针确实存在,您可以将 char 指针转换为另一个指针。 见Strict aliasing rule and 'char *' pointers

【讨论】:

  • 关于您的建议...如果您执行 typedef void ipv4hdr,那么 ip4hdr* 将是一个 void 指针,与所有其他 void 指针类型兼容,例如 etherhdr*。因此,虚拟结构是必要的。
  • 扩展@juhist 所写的内容:在您的建议中,误用不会给出编译器警告,这是重点。
【解决方案2】:

该标准允许实现对比其中包含的任何项目更粗糙的结构施加对齐限制。这将允许一个仅支持对齐访问的平台的实现,例如:

#include <string.h>
#include <stdint.h>
struct foo {uint32_t dat[1]; };
struct bar {uint16_t dat[2]; };
void test1(struct foo *dest, struct foo *src)
{
    memcpy(dest, src, 4);
}
void test2(struct bar *dest, struct bar *src)
{
    memcpy(dest, src, 4);
}

test2 生成与test1 一样高效的代码[使用一次32 位读取和写入,而不是两次16 位读取和写入]。如果实现总是将所有结构填充到四字节的倍数并将它们对齐到四字节边界,则允许这样的实现在 test2 上执行上述优化,而无需知道或关心如何甚至如果 struct bar 曾经在任何地方定义过。

我不知道目前的实现是否会做这样的事情,但我很难排除未来的实现可能会这样做的可能性,因为在某些情况下它可以允许更有效的代码生成。

【讨论】:

    猜你喜欢
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    • 2016-10-09
    • 2020-02-08
    相关资源
    最近更新 更多