我已经看过标准但是找不到任何迹象表明简单地写入内存将被视为可观察的行为。如果不是,那就意味着编译的代码不需要实际写入该内存。如果编译器选择优化此类访问,则涉及映射器内存或共享内存的任何内容都可能无效。
1.9-8似乎定义了非常有限的可观察行为,但表明实现可能定义更多。可以假设任何质量编译器都会将修改内存视为可观察行为吗?也就是说,它可能不保证原子性或排序,但确保最终会写入数据。
那么,我是否忽略了标准中的某些内容,或者仅仅是编译器决定要写入内存?
来自当前或C ++ 0x标准的语句是好的。请注意我不是在谈论通过函数访问内存,我的意思是直接访问,例如将数据写入指针(可能通过mmap或其他库函数检索)。
答案 0 :(得分:9)
这种事情是volatile
存在的。另外,写入记忆并且从不显然从中读取是不可观察的行为。但是,在一般情况下,优化器很难证明你从来没有读过它,除非是相对简单的例子,所以它通常不是问题。
答案 1 :(得分:2)
可以假设任何质量编译器都会将修改内存视为可观察的行为吗?
没有。挥发性用于标记。但是,即使在添加volatile限定符之后,您也无法完全信任编译器,至少在2008年的论文中有所说明:http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf
修改强>
来自C标准(不是C ++)http://c0x.coding-guidelines.com/5.1.2.3.html
实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用并且没有产生所需的副作用(包括由调用函数或访问volatile对象引起的任何副作用)。
答案 2 :(得分:1)
我对C99的解读是,除非您指定volatile
,否则实际访问变量的方式和时间是实现定义的。如果指定volatile
限定符,则代码必须根据抽象机的规则工作。
标准中的相关部分包括:6.7.3 Type qualifiers
(volatile
说明)和5.1.2.3 Program execution
(抽象机器定义)。
一段时间以来,我知道许多编译器实际上都有启发式方法来检测应该重新读取变量以及何时可以使用缓存副本的情况。易失性使编译器清楚地知道对变量的每次访问实际上都应该是对内存的访问。没有volatile,似乎编译器可以自由地重新读取变量。
BTW包装函数中的访问并没有改变,因为即使没有内联的函数仍然可能仍被当前编译单元内的编译器内联。
从下面的问题:
假设我在堆上使用一个数组(未指定分配的位置), 我使用该数组执行计算(临时空间)。该 优化器看到它实际上并不需要任何空间 可以严格使用寄存器。编译器是否仍然编写了 温度值到内存?
以下每个MSalters:
不保证,也不太可能。考虑一个静态单一 分配优化器。这表明每个可能的写/读 依赖项,然后分配寄存器以优化这些依赖项。 作为副作用,任何未被(可能)读取的写入 根本不创建依赖关系,并且被消除。在你的例子中 (“严格使用寄存器”)优化器已满足所有写入/读取 与寄存器的依赖关系,因此它根本不会写入内存。所有 读取产生正确的值,因此这是一个正确的优化。