【问题标题】:How can I determine if I'm overparenthesizing?如何确定我是否过度使用括号?
【发布时间】:2019-08-20 12:07:28
【问题描述】:

我目前正在尝试避免 C 中的指针算术工作来编写模拟器。

通常,如果您将1 添加到 C 中的指针,则改为添加指向对象的大小。但是,我正在尝试使用位和字节,所以这是不希望的。

我想知道我在这个例子中是否使用了太多括号:

*(int16_t *)(((intptr_t)bc)+sp)

如果不是,那么它是否等同于这个? :

*(int16_t *)((intptr_t)bc+sp)

sp 是我的模拟器的页面对齐堆栈地址(通过mmap 获得,没有设置MAP_FIXED)。它是一个intptr_t 类型。

bcint16_t * 类型的名称。它是一个指向两个int8_t 组合的指针。

【问题讨论】:

  • "你添加了指针的大小" --> 不完全。代码添加指向对象的大小。
  • bcint16_t * 类型的名称。它是一个指向两个int8_t 组合的指针。 这听起来像是strict aliasing 违规。您不能安全地获取一种类型的对象并将其视为另一种类型。在这种情况下,您不能假设两个int8_t 值可以作为int16_t 值安全访问,即使这两个int8_t 值在内存中是相邻的。
  • 注意@AndrewHenle 的警告。你似乎在这里涉足危险领域。
  • 成为结构中的对象并不能免除您违反严格别名的行为。如果你想绕过它,你可以使用联合来输入双关。
  • @JL2210 你应该写一个关于如何键入双关的新问题,并包含显示你如何做的代码,我们可以更详细地了解这个问题,而不是在这个问题上切线.您可以留下对这个问题的参考,提到新问题是对此的后续。

标签: c emulation pointer-arithmetic


【解决方案1】:

(((intptr_t)bc)+sp) 等价于((intptr_t)bc+sp)


但是整个“避免指针算术”方法是不可移植的。

至少 3 个问题:

  • 转换为整数的指针当然不能保持所需的数学属性。

    // possible outcome
    uint16_t x[2];
    printf("%llx\n", (unsigned long long) (intptr_t) &x[0]); // --> abcd0000
    printf("%llx\n", (unsigned long long) (intptr_t) &x[1]); // --> abcd0010
    

整数的差异可能是 16,而不是希望的 2——即使 2 的差异更常见。

  • 此外,对于*(int16_t *)((intptr_t)bc+sp),如果sp 是奇数,(int16_t *) 可能由于对齐限制而失败。

  • 也会出现抗锯齿问题。 @Andrew Henle

虽然整数这样避免指针算术有各种陷阱 - 祝你好运。

【讨论】:

  • ...一年多后,我意识到自己是多么愚蠢。
【解决方案2】:

您要问的是运算符优先级。完整列表可以在here. 找到

“+”操作发生在类型转换操作之后。因此,您不需要第二层括号,因为intptr_t 转换首先应用于bc,然后将结果添加到sp

【讨论】:

  • 很抱歉不接受一个答案,但差不多一年后我意识到另一个答案是更好的建议。
猜你喜欢
  • 2012-02-03
  • 1970-01-01
  • 2022-08-13
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 2015-05-16
  • 2017-03-31
  • 2010-10-15
相关资源
最近更新 更多