C 为什么'volatile'变量的值不';你不会变吗?

C 为什么'volatile'变量的值不';你不会变吗?,c,C,我试图准确地理解C的基础知识,volatile关键字 它似乎不像我想的那样起作用。 我在某处读到: volatile指定可以通过操作修改与var关联的值 除了附近代码中的代码。 当一个变量声明为volatile时,编译器将从重新加载该值 每次程序访问内存时,它都会返回内存。 这通过优化编译器来防止优化。 它主要用于确保可预测的程序行为 我有两个程序,由两个不同的.c文件编译而成 start\u loop具有名为done的全局int变量,以0作为初始值,无限循环应测试done值是否已更改为1。它还

我试图准确地理解C的基础知识,
volatile
关键字

它似乎不像我想的那样起作用。 我在某处读到:

volatile
指定可以通过操作修改与var关联的值 除了附近代码中的代码。 当一个变量声明为volatile时,编译器将从
重新加载该值 每次程序访问内存时,它都会返回内存。 这通过优化编译器来防止优化。 它主要用于确保可预测的程序行为

我有两个程序,由两个不同的
.c
文件编译而成

start\u loop
具有名为
done
的全局
int
变量,以
0
作为初始值,无限循环应测试
done
值是否已更改为
1
。它还将
done
变量的地址输出到
stdout

启动循环
程序:

#include <stdio.h>
#include <time.h>

volatile int done = 0;
void delay(int seconds){
    // some logic for time delay here
    }

void main() {
    while (done !=1){
        delay(4);
        printf("adress of `done`: %p\nvalue: %d\n", &done, done);
    }
}
当我在第一个终端选项卡中启动
start\u循环
程序时,我得到:

4 seconds delay passed
#1
adress of `done`: 0x601048
value: 0

4 seconds delay passed
#2
adress of `done`: 0x601048
value: 0

...
在第二个终端选项卡中,我启动了
change\u done\u var\u值,并将
0x601048
传递给它:

got the address as first arg(str): 0x601048 -> adress/value 0x601048/0
change `done` to 1?
y
changed
new value: 1
start\u loop
程序仍在运行:

4 seconds delay passed
#46
adress of `done`: 0x601048
value: 0
似乎
change\u done\u var\u值
程序获得了正确的
地址
值,因为它在取消引用指向
done
变量的指针时显示了正确的
0

我需要做些什么才能使事情正常进行(从
更改
完成值
更改
更改
完成值并停止执行
启动循环
程序)? 或者不是这样的

除附近代码中的操作以外的其他操作

对,;这意味着可以修改相应的内存块。通常,这将是同一程序中的不同线程。在某些特定于平台的情况下,您可能会将变量安排在对操作系统(或硬件)具有特殊意义的特定位置;例如,在旧的手持设备或控制台上,您可以从表示I/O寄存器的虚拟内存位置进行读取,以了解键盘上按下了什么按钮。通过使用
volatile
,编译器将了解必须检查该值,因为硬件可能已写入该内存,而您的程序依赖于了解更改


在现代台式计算机上,程序具有内存保护和内存空间虚拟化。他们无法轻松查看彼此的数据,通常需要一些特殊安排/许可。但即使有可能,也不能简单地使用另一个程序的名称来检查它的变量——这个名称只对编译器有意义;它不是已编译程序的实际部分(尽管调试模式编译可能会尝试使其以这种方式运行)。

如果我理解正确,您是否尝试在另一个程序中使用一个程序的内存?在任何现代操作系统上“它都不是这样工作的”,因为程序(或者更好地说:“进程”)是有目的地封装的,如果没有特定于操作系统的进程间通信库函数,它们就无法访问其他进程的内存。您可以在此网站上阅读更多关于它们的信息,以及如何在基于Linux的操作系统中使用它们:

很抱歉,我无法进一步阐述,因为我从未在通用桌面操作系统上使用过内部进程间通信

使用socket API还有一个更为重要的选择(它通常可以在全世界不同的PC网络中使用)。使用socket API并不困难,在大学的网络讲座课程中讲授。然后,您将得到“服务器”和“客户端”程序,您必须注意一些“原语”,它们必须按特定顺序调用。 教程的一个常见来源似乎是

这种保护机制称为内存虚拟化。它使得每个进程都使用自己的虚拟地址空间,这与其他进程的虚拟地址空间不同。或简要说明:不同程序中的相同地址将导致实际内存中的不同物理地址

在我看来,这里的设计错误是编译两个不同的程序来完成任务。通常的做法是只编译一个使用多线程的程序(这意味着执行多个线程),因为多线程比进程间通信更轻,而且可能更容易使用(至少我知道怎么做)。对于多线程,您可以在基于Linux的系统中使用pthread库,如果我没有记错的话,可以使用-pthread命令行选项将其包含在程序中


快乐编码

稍微修改一下代码。在第一个程序中,初始化done to
25
(或一些非零值)。你可能会发现你给第二个程序的地址实际上并不正确。你有一个基本的误解。每个进程在单独的地址空间中运行。一个进程中的地址A与另一个进程中的地址A的数据不同。我想确保我理解正确。您有两个完全独立的程序同时运行,并且您希望它们知道彼此内存中的值。。。因为当您为它们编写代码时,您对全局变量使用了相同的名称?事实上,其中一个项目甚至不是全球性的?请仔细考虑一下,如果它是按照你想象的方式工作的话,它的含义。任何人只要猜测他们使用的变量名就可以在计算机上破解任何其他人的程序。这是令人惊讶的。(见@kaylum的评论。)平台是什么?@pospolitaki仔细看看你的评论。在第二个程序中,您没有看到25。
4 seconds delay passed
#46
adress of `done`: 0x601048
value: 0