这个 gcc/clang 过去一指针比较行为符合还是非标准?

2024-03-20

尽管 C 标准明确认识到这样一种可能性,即指向“刚刚过去”一个对象的地址可能会偶然与指向“指向”另一个不相关对象的地址进行比较,但 gcc 和 clang 似乎都在假设没有指针的情况下进行操作观察到的指向刚刚经过一个对象的对象可能指向另一个对象,如以下示例所示:

#include <stdio.h>

int x[1],y[1];
int test1(int *p)
{
    y[0] = 1;
    if (p==x+1)
        *p = 2; // Note that assignment is to *p and not to x[1] !!!
    return y[0];
}
int test2(int *p)
{
    x[0] = 1;
    if (p==y+1)
        *p = 2; // Note that assignment is to *p and not to y[1] !!!
    return x[0];
}

int (*volatile test1a)(int *p) = test1;
int (*volatile test2a)(int *p) = test2;

int main(void) {
    int q;
    printf("%llX\n",(unsigned long long)y - (unsigned long long)x);
    q = test1a(y);
    printf(">> %d %d\n", y[0], q);
    q = test2a(x);
    printf(">> %d %d\n", x[0], q);
    return 0;
}

通过我对标准的阅读,该程序在标记行上的有效输出>>会是>> 1 1 or >> 2 2,但是 ideone 上的 gcc 输出>> 2 1对于其中一行,据我所知,由 clang 生成的代码也会对另一行执行同样的操作。

我很清楚事实是p比较等于x[1]并不意味着后一个表达式可用于访问与以下内容相同的对象*p(或任何对象,就此而言),但我不知道标准中没有任何内容禁止计算x+1也不比较结果指针和p。我也不知道有什么会导致这种比较p无法用于访问其保存地址的对象。

对 C 标准的任何已发布版本或草稿版本是否有任何合理的解读,在该版本中,上述代码会调用未定义的行为,或者从test1 and test2不需要匹配最终值y[0] or x[0]分别,或者 clang 和 gcc 中的优化器是否设计用于处理不是标准的已发布版本或草稿版本的方言?

PS--来自标准草案 N1570 6.5.9p6:

6 两个指针比较相等当且仅当两者都是空指针,并且都是指向 相同的对象(包括指向对象的指针和其开头的子对象)或函数, 两者都是指向同一数组对象最后一个元素之后的指针,或者一个是指针 一个指向一个数组对象的末尾,另一个是指向另一个数组对象的开头的指针 恰好紧随地址中第一个数组对象的数组对象 空间。

该标准并不以任何方式暗示x[]必须遵循y[]反之亦然,但似乎明确提供了指向刚刚过去的指针的可能性x可能会比作y并且观察到是相等的。


这确实是一个编译器错误。大多数情况下,当p == x+i对于某些指针评估为 truep, array x,和整数i,确实如此p必然指向其中的一个元素x(或者程序正在执行具有未定义行为的代码,在这种情况下,允许编译器假设p指向一个元素x). If p确实指向了一个元素x,这确实是*p = 2;不能变y[0],因此编译器生成返回最近分配给的 1 的代码是正确的y[0]。线索表明编译器已尝试进行优化,其中“学习”了p通过比较的真实性。

当以下情况时,此扣除失败x+i指向数组末尾之外的一个x。在 C 2018 6.5.9 6 中,标准告诉我们,这种比较可能评估为 true,即使p指向一个不同的对象,与x(但这恰好在记忆中紧随其后)。编译器的推导应该更加有限。给定p+j == x+i, where x是一个数组n元素,评估为真这一事实仅意味着p+k指向一个元素x for jik < n+ji。 (在问题中的情况下,i=1, j=0, and k=0,则 0−1 ≤ 0

(请注意,对于问题中的情况,上述标准意味着p-1指向一个元素x,因为 0−1 ≤ −1 p指向y并且对于指向无效x。但用它来访问p[-1]具有标准未定义的行为,这意味着允许任何假设,包括p[-1]是一个元素x。因此编译器被允许使用该标准。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这个 gcc/clang 过去一指针比较行为符合还是非标准? 的相关文章

随机推荐

  • 使用出生日期计算年龄

    我正在开发一个 Android 应用程序 用于从用户提供的出生日期查找年龄 三个编辑文本 一个代表天 另外两个代表月份和年份 我从中得到了代码link http www androidsnippets com calculate age 但
  • es6 承诺吞下类型错误

    我希望浏览器在发生类型错误时显示错误消息 错误如无法读取未定义的属性 or 未定义参考 new Promise function resolve reject do stuff reject something logical is wro
  • 处理随机建筑绘图窗口问题

    我重新发布此内容是因为我第一次发布此内容时代码不正确 我已经把所有的事情都记下来了 看起来像这样 但它应该看起来像这样 任何帮助使窗户与建筑物对齐都会很棒 因为我对此很陌生 谢谢 int buildingHeights new int 12
  • 在数组中搜索匹配的字符串

    我正在寻找方法来检查字符串是否作为数组值存在于数组中是否可能 我将如何使用 PHP 来做到这一点 如果您只是想知道它是否存在 请使用in array http php net manual en function in array php
  • AmbigeousMatchException - Type.GetProperty - C# 反射

    昨天我在开发 Web 部件时遇到了一个问题 这个问题不是关于 webpart 而是关于 C 关于这个问题的背景很少 我有一个使用 Reflection 加载 WebPart 的代码 其中我得到了 AmbigouslyMatchExcepti
  • 酿造服务。无法启动服务。得到“引导失败:5:输入/输出错误”

    running brew services start mongodb community产生 Bootstrap failed 5 Input output error Error Failure while executing bin
  • int(x[base]) 如何工作?

    以下代码的输出是 int 12 5 O P 7 int 0 5 O P 0 int 10 2 O P 2 我无法理解这一点 Python 文档中说 base 部分是可选的 即它可能需要一个或两个参数 第一个参数必须是一个在引号内具有 int
  • 在 Dockercontainer 中安装 MariaDB - 需要 MariaDB Connector/C >= 3.2.4,发现版本 3.1.16

    我尝试构建以下 Dockerfile FROM python 3 10 ENV TZ Europa Berlin install google chrome RUN wget q O https dl ssl google com linu
  • ng-change 不适用于 ng-select

    我正在使用一个由以下内容填充的选择框ng options 不幸的是 我无法得到我的ng change要调用的函数 这是我的小提琴 http jsfiddle net MTfRD 1097 这是我的js var myApp angular m
  • 什么是最好的 UTF [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 使用 Spring Boot 和 Netflix Zuul 的简单反向代理

    我正在寻找使用 Spring Boot 实现一个简单的反向代理 即 轻松添加路线 能够在每个路由的基础上添加自定义身份验证 根据需要添加其他标头 我查看了提供的设施 EnableZuulProxy注释 但它似乎太重量级了 因为我不想使用 E
  • html 表格中的等高缩放单元格

    当我进行此设计时 我在使用 HTML 表格时遇到了一些问题 左侧单元格是 rowspan 2 单元格 右侧两个单元格使用 height 50 属性 以下是预期的行为 Equal height cell 1 Scaling height ce
  • 为什么我的视图右上角有一个“加号”图标?

    我正在尝试为我的应用程序实现拖放功能LazyHGridview 当我尝试将视图放到另一个视图上时 视图的右上角会显示一个绿色圆圈内的 加号 图标 struct TestView View var d GridData Binding var
  • clrscr() 无法在 VC++(VS 2008) 中工作......?

    在 VS 2008 中 我在 VC 中创建了一个空项目 并添加了一个源文件作为 include
  • iOS 共享扩展不适用于图像网址

    我有一个使用这些规则的共享扩展
  • 什么时候应该使用布尔值而不是布尔值? [复制]

    这个问题在这里已经有答案了 什么时候应该使用布尔值而不是布尔值 我的意思是 为什么我想在应该包含 true 或 false 的变量中包含一个空值 大多数人 一个自发的答案是 如果该值未知 即 如果我们不知道该值是真还是假 但从编程的角度来看
  • 简单的域名正则表达式

    如何确保域名符合这 3 个简单标准 以 com net 结尾 不得以 http 或 https http www 或 https www 我已经设法理解了正则表达式的这一部分 它与第一个标准相对应 com net 但我不知道如何实现另外两个
  • 如何“执行”make文件

    我尝试在 code blocks 中使用 make 文件 但我做错了 我安装了包含编译器的版本 http sourceforge net projects codeblocks files Binaries 10 05 Windows co
  • Stripe 支付:来源与令牌/卡?

    我正在努力使用 stripe 设置定期付款 我正在使用react stripe elements来收集卡片信息 看起来有两种方法可以保存卡片供以后使用 this props stripe createToken this props str
  • 这个 gcc/clang 过去一指针比较行为符合还是非标准?

    尽管 C 标准明确认识到这样一种可能性 即指向 刚刚过去 一个对象的地址可能会偶然与指向 指向 另一个不相关对象的地址进行比较 但 gcc 和 clang 似乎都在假设没有指针的情况下进行操作观察到的指向刚刚经过一个对象的对象可能指向另一个