为什么编译器会优化掉由于 strncmp() 而导致的共享内存读取,即使使用了 volatile 关键字?

2024-03-14

这是一个程序foo.c将数据写入共享内存。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main()
{
    key_t key;
    int shmid;
    char *mem;

    if ((key = ftok("ftok", 0)) == -1) {
        perror("ftok");
        return 1;
    }

    if ((shmid = shmget(key, 100, 0600 | IPC_CREAT)) == -1) {
        perror("shmget");
        return 1;
    }

    printf("key: 0x%x; shmid: %d\n", key, shmid);

    if ((mem = shmat(shmid, NULL, 0)) == (void *) -1) {
        perror("shmat");
        return 1;
    }

    sprintf(mem, "hello");
    sleep(10);
    sprintf(mem, "exit");

    return 1;
}

这是另一个程序bar.c从同一共享内存中读取数据。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main()
{
    key_t key;
    int shmid;
    volatile char *mem;

    if ((key = ftok("ftok", 0)) == -1) {
        perror("ftok");
        return 1;
    }

    if ((shmid = shmget(key, sizeof (int), 0400 | IPC_CREAT)) == -1) {
        perror("shmget");
        return 1;
    }

    printf("key: 0x%x; shmid: %d\n", key, shmid);

    if ((mem = shmat(shmid, NULL, 0)) == (void *) -1) {
        perror("shmat");
        return 1;
    }

    printf("looping ...\n");
    while (strncmp((char *) mem, "exit", 4) != 0)
        ;

    printf("exiting ...\n");

    return 0;
}

我首先在一个终端中运行 writer 程序。

touch ftok && gcc foo.c -o foo && ./foo

当写入器程序仍在运行时,我在另一个终端中运行读取器程序。

gcc -O1 bar.c -o bar && ./bar

阅读器程序进入无限循环。看起来优化器已经优化了以下代码

    while (strncmp((char *) mem, "exit", 4) != 0)
        ;

to

    while (1)
        ;

因为它在循环中看不到任何可以修改数据的内容mem读过一次后。

但我宣布mem as volatile正是因为这个原因;以防止编译器对其进行优化。

volatile char *mem;

为什么编译器仍然优化掉读取mem?

顺便说一下,我找到了一个有效的解决方案。有效的解决方案是修改

    while (strncmp((char *) mem, "exit", 4) != 0)
        ;

to

    while (mem[0] != 'e' || mem[1] != 'x' || mem[2] != 'i' || mem[3] != 't')
        ;

为什么编译器会优化掉strncmp((char *) mem, "exit", 4) != 0但并没有优化掉mem[0] != 'e' || mem[1] != 'x' || mem[2] != 'i' || mem[3] != 't'虽然char *mem被声明为volatile在这两种情况下?


6.7.3 类型限定符

6 [...] If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.133)

133) This applies to those objects that behave as if they were defined with qualified types, even if they are never actually defined as objects in the program (such as an object at a memory-mapped input/output address).

这正是您在代码中观察到的。编译器基本上是在“行为无论如何都未定义”的狂野自由下优化您的代码。

换句话说,不可能正确应用strncmp直接到易失性数据。

你可以做的就是实现你自己的比较,不丢弃volatile限定符(这是您已经完成的),或者使用一些易失性感知方法将易失性数据复制到非易失性存储,并且它们适用strncmp到后者。

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

为什么编译器会优化掉由于 strncmp() 而导致的共享内存读取,即使使用了 volatile 关键字? 的相关文章

随机推荐

  • VBA .SetText 和 .PutInClipboard 将两个符号而不是所需数据放入剪贴板

    使用 Excel 2016 和对 Microsoft Forms 2 0 对象库的引用 我尝试将 ActiveCell 的内容复制到剪贴板 相反 我的剪贴板的结果内容是以下 2 个符号 如果它们实际上显示在此文本字段中 如果这些符号没有渲染
  • countForFetchRequest 对于空表返回 1

    我正在执行 countForFetchRequest 它总是返回比表中记录数多 1 的计数 NSFetchRequest request NSFetchRequest alloc init request setEntity NSEntit
  • 如何修复“AVDRegister - AppleAVDCheckPlatform() 返回 FALSE”

    我使用此代码来检查我的 iPhone 是否支持 hevc 硬解码 BOOL hardwareDecodeSupported VTIsHardwareDecodeSupported kCMVideoCodecType HEVC 但在控制台上我
  • Silverlight 请求、失败和 Fiddler

    我有一个发出跨域请求的 Silverlight 应用程序 clientaccesspolicy xml 文件存在于我发出请求的服务器上并且配置正确 我知道它配置正确 因为当我使用该应用程序发出请求时我的机器我收到了没有问题的回复 当大约 3
  • 在 React 上导入多个图像

    我正在尝试构建一个反应应用程序 并且必须使用多个图像 现在我必须导入我将使用的每个图像 例如 import image from img img1 png img src img 或者还有其他方法吗 PS 我尝试过 require 它也给出
  • 常量 Flask 会话 ID

    I ve a Flask应用程序 使用 Nginx WSGI FastCGI 和 Gevent 提供服务并使用标准 Flask 会话 我愿意not使用session permanent True或任何其他额外选项 但只需设置SECRET K
  • 在 Python 中打印“批准”符号/复选标记 (✓) U+2713

    如何在Python中打印复选标记 这是批准的标志 而不是平方根 您可以使用转义序列打印任何 Unicode 字符 确保创建一个 Unicode 字符串 print u u2713
  • git 中预推送和预接收钩子的区别?

    git 中的预推送和预接收钩子在用例或工作逻辑方面有区别吗 我能理解的唯一区别是他们文档 https github com git git blob master Documentation githooks txt L211就他们收到的输
  • 是否可以定义相互依赖的类型并在单独的文件中定义?

    我正在尝试实现一个具有扩展解析功能的库 我决定使用 fsyacc 因为我从大学就知道它 不幸的是我遇到了以下问题 我为我的语法头部定义了一个类 Head 并将其实现放在一个文件中 然后我将解析器定义为 start head type hea
  • 最小元素错误

    我不是 C 编码员 所以也许这很容易 我有一个 Point 类向量 我想找到 AABB 矩形 最小 x 最小 y 最小 x 最大 y 最大 x 最小 y 最大 x 最大 y 我已经完成了一个 for 循环 保存最小值和最大值 一次用于 x
  • 强制链接与库不同的 SONAME

    如何以与具有冲突 SONAME 的库的两个现有版本兼容的方式链接二进制文件 这两个版本不共享相同的 SONAME 前缀 一个是 libcapi10 so 3 另一个是 libcapi10 so 4 我无法重新编译它们 因为我将它们作为二进制
  • 在Python中反转列表切片

    我试图在 python 中反转列表的切片 但它返回一个空列表 但是当我尝试使用整个列表时 它工作得很好 我在这里错过了什么吗 l 1 2 3 4 5 6 7 8 l 1 8 7 6 5 4 3 2 1 lt lt lt This worke
  • Flink CEP:对于不同类型的事件,使用哪种方法加入数据流?

    假设我有两种不同类型的数据流 一种提供天气数据 另一种提供车辆数据 我想使用 Flink 对数据进行复杂的事件处理 Flink 1 3 x 中哪种方法是正确的使用方法 我看到了不同的方法 如 Union Connect Window Joi
  • 获取 iframe 的源代码

    有没有办法获取 iframe 加载的页面的源代码 我不想更改任何代码 我只想阅读它 我还需要能够使用 javascript html 来获取它 document getElementById iframeID contentWindow d
  • Swift 2 中“kGMSMarkerAnimationPop”错误的使用不明确

    我在尝试为 GMSMarker 制作动画时遇到错误 我已遵循 Google 文档和各种指南 但它不断返回错误 下面是我的代码 func placeMarker coordinate CLLocationCoordinate2D if loc
  • g++ 链接问题:对函数的未定义引用

    我使用 CMake 和 Visual C 构建 HyDE 库 然后 仍然在 VC 中 我能够成功创建代码并构建链接到 HyDE lib 和 HyDE 头文件的可执行文件 然后我发现 为了与我公司的其他人一起工作 最好在 Eclipse CD
  • 复选框树

    我正在寻找 Javascript 的 复选框树 小部件 我尝试使用jquery 检查树 http jquery checktree googlecode com 其声称完全符合我的要求 但它存在以下问题 它无法识别已选中的复选框 并将所有内
  • 查找用户是否是 Active Directory 组 ASP.NET VB 的成员?

    我正在使用 Active Directory 对 Intranet 站点的用户进行身份验证 我想根据用户在 Active Directory 中所在的组来优化经过身份验证的用户 有人可以向我展示或指出如何在 ASP NET 4 0 VB 中
  • 在 Angular 2 中使用 ngForTemplate 时绑定事件

    假设我有这个简单的列表渲染组件 import Input Component from angular2 core Component selector my list template div item div class MyList
  • 为什么编译器会优化掉由于 strncmp() 而导致的共享内存读取,即使使用了 volatile 关键字?

    这是一个程序foo c将数据写入共享内存 include