【问题标题】:How to dereference and autoincrement a cast pointer in C?如何在C中取消引用和自动增加强制转换指针?
【发布时间】:2016-01-19 23:52:08
【问题描述】:

我在浏览一些非结构化数据时使用了纯 C 语言的void*,我想在进行时使用取消引用和自动增量进行转换。我想写以下内容:

void* ptr = /*something*/;
uint16_t i = *((uint16_t*) ptr)++;

编译器对象并告诉我“需要作为增量操作数的左值”,但我想我认为将指针转换为指针仍然可以作为左值。

很明显,我的意图是让 ptr 现在指向比之前指向的位置多两个字节。我无法删除 ptr 演员表周围的括号,因为 ++ 的优先级高于演员表,所以这不会像我想要的那样工作:

int i = *(uint16_t*) ptr++;

我当然可以自己递增,如下所示,但我希望得到一些优雅而简洁的东西:

int i = *(uint16_t) ptr;
ptr += sizeof(uint16_t);

有什么好的方法可以做到这一点?

【问题讨论】:

  • "我当然可以..." - 实际上这是不可能的,你不能对 void 指针进行算术运算
  • @M.M:嗯,gcc 确实允许将其作为扩展名(行为类似于char *)。当然,这并不意味着你应该这样做。
  • 如果您有一些八位字节的数据流并想从中提取更大的类型(反序列化),请使用移位/屏蔽。不要依赖“有问题的”功能(没有实际需要)。
  • *((uint16_t*) ptr)++; ??
  • 为了 gore 的利益,*(*(uint16_t **)&ptr)++ 可能会起作用,尽管它会由于别名违规而导致未定义的行为

标签: c pointers casting


【解决方案1】:

写起来最简单:

uint16_t *uptr = ptr;
uint16_t i = *uptr++;
ptr = uptr;            // if required

您也许可以重组较大的代码以尽可能多地使用uint16_t *,从而无需进行如此多的转换。

【讨论】:

  • 我认为这是另一个(反)序列化/编组问题。我真的很想知道正确地做这件事有什么复杂的。
  • @MM,谢谢。我很遗憾我还没有足够的声誉来支持你的答案。但uint16_t*只是作为一个例子,不一定代表数据的典型案例。
  • @Olaf:“我真的很想知道正确地做这件事有什么复杂的。”缺乏经验? ;-) 老实说,我没有做很多序列化,而且当我这样做时,通常使用我定义的结构良好的数据。这是一个我只想执行一些简单操作并继续前进的案例。
  • @JoshSanford:也许我对这些东西太深入了。我应该改用 3D 图形编程;-) 但实际上只需要两个小而通用的函数(除非你有一些没有 8 位字节的奇异系统):每个方向一个。
【解决方案2】:

很长一段时间以来,都不允许将指针强制转换为不同的类型,可能从 C89 开始。原因是从一种类型的指针到另一种类型的转换会改变表示,因此可能不会引用同一个对象。

您必须将表达式拆分为 2 个语句:

void *ptr = /*something*/;
uint16_t i = *(uint16_t*)ptr;
ptr = (uint16_t*)ptr + 1;

或者,如果针对单个表达式的上下文命令,您可以使用这个技巧:

uint16_t i = ((uint16_t*)(ptr = (uint16_t*)ptr + 1))[-1];

如果您想进一步混淆,或者这个:

uint16_t i = (-1)[(uint16_t*)(ptr = (uint16_t*)ptr + 1)];

【讨论】:

猜你喜欢
  • 2016-08-29
  • 1970-01-01
  • 2015-10-05
  • 2015-07-03
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
  • 1970-01-01
  • 2015-10-15
相关资源
最近更新 更多