写入内存是否为可观察的行为
Is writing to memory an observable behaviour?
我看过标准,但没有发现任何迹象表明,简单地写入内存将被视为可观察的行为。如果不是,则意味着编译后的代码实际上不需要写入该内存。如果编译器选择优化这种访问,任何涉及映射器内存或共享内存的东西都可能无法工作。
1.9-8似乎定义了一个非常有限的可观察行为,但表明实现可以定义更多。可以假设任何高质量的编译器会把修改内存作为一种可观察的行为吗?也就是说,它可能不能保证原子性或排序,但可以保证数据最终会被写入。
那么,我是否忽略了标准中的某些内容,或者仅仅是编译器决定要做的事情?
来自当前或c++ 0x标准的语句很好。请注意,我不是在谈论通过函数访问内存,我的意思是直接访问,例如将数据写入指针(可能通过mmap或其他库函数检索)。
这就是volatile
存在的意义。否则,写入内存而从未明显地从内存中读取是不可观察的行为。然而,在一般情况下,优化器几乎不可能证明您从未回读它,除非在相对较小的示例中,所以这通常不是问题。
可以假设任何高质量的编译器都会将修改内存视为可观察的行为吗?
。Volatile就是用来标记它的。但是,即使在添加了volatile限定符之后,也不能完全信任编译器,至少2008年的一篇论文是这样说的:http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf
编辑:源自C标准(非c++) http://c0x.coding-guidelines.com/5.1.2.3.html
如果可以推断出表达式的值没有被使用,并且没有产生必要的副作用(包括调用函数或访问易失性对象所引起的任何副作用),则实际实现不需要计算表达式的部分。
我对C99的理解是,除非您指定volatile
,否则如何以及何时实际访问变量是实现定义的。如果指定volatile
限定符,则代码必须按照抽象机的规则工作。
标准中相关部分为:6.7.3 Type qualifiers
(volatile
描述)和5.1.2.3 Program execution
(抽象机器定义)。
一段时间以来,我知道许多编译器实际上有启发式来检测何时应该重新读取变量以及何时可以使用缓存副本。Volatile使编译器清楚地知道,对变量的每次访问实际上都应该是对内存的访问。没有volatile,编译器似乎永远不会重新读取变量。
顺便说一句,在函数中包装访问并不会改变这一点,因为即使没有内联的函数仍然可能被编译器内联在当前编译单元内。
从你下面的问题:
假设我在堆上使用一个数组(未指定分配的位置),我用这个数组来执行一个计算(临时空间)。的Optimizer看到它实际上不需要任何空间能严格使用寄存器。编译器还是会写内存的临时值?
不能保证,也不太可能。考虑一个静态单分配的优化器。这计算出每个可能的写/读依赖,然后分配寄存器来优化这些依赖项。作为副作用,任何写操作之后没有(可能的)读操作不创建任何依赖项,并被消除。在你的例子中("严格使用寄存器")优化器已经满足了所有的写/读与寄存器的依赖关系,因此它根本不会写入内存。所有读取产生正确的值,所以这是一个正确的优化。
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 是否可以使用松弛的内存顺序来观察条件?
- C++11如何观察原子::存储和原子::加载中的内存顺序
- 写入内存是否为可观察的行为