我有一个理论(非确定性,难以测试,从未发生在实践中)硬件问题报告硬件供应商,其中双字写入特定内存范围可能破坏任何未来的总线传输。
虽然我在C代码中没有任何明确的双词写入,但我担心编译器(在当前或未来的实现中)被允许将多个相邻的词赋值合并为单个双词赋值。
编译器不允许对Volatile的赋值进行重新排序,但(对我来说)不清楚合并是否算作重新排序。我的直觉是这样的,但我以前被语言律师纠正过!
示例:
typedef struct
{
volatile unsigned reg0;
volatile unsigned reg1;
} Module;
volatile Module* module = (volatile Module*)0xFF000000u;
// two word stores, or one double-word store?
module->reg0 = 1;
module->reg1 = 2;
(我会单独询问我的编译器供应商,但我很好奇标准的规范/社区解释是什么。)
对于易失性对象上的操作和实际机器上的操作之间的任何关系,C标准是不可知的。虽然大多数实现将指定像*(char volate*)0x1234=0x56;
这样的构造将生成值为0x90的字节存储到硬件地址0x1234,但一个实现可以在空闲时为例如8192字节数组分配空间,并指定*(char volate*)0x1234=0x56;
将立即将0x56存储到该数组的元素0x1234,而不必对硬件地址0x1234做任何事情。可替换地,实现可包括某些进程,该进程将碰巧在该阵列的0x1234中的任何内容周期性地存储到硬件地址0x56。
从抽象机器的角度来看,对单个线程内易失性对象的所有操作都被视为绝对有序的,这才是一致性所需要的。从标准的观点来看,实现可以以他们认为合适的任何方式将这样的访问转换为真实的机器操作。
请考虑以下简单代码: https://godbolt.org/z/i2kby7 您可以看到和都没有优化对的潜在调用。在我的理解中,这是正确的:抽象机器假设变量随时可能发生变化(例如,由于是硬件映射的),因此将初始化常数折叠为检查将是错误的。 > 这里讨论了消除对的读写操作:允许编译器优化本地volatile变量吗?(谢谢内森!)。我认为标准是非常清楚的,那些读写必须发生。但是这些讨论并不包括编译器
IE 可能会失败。 C11附件J.2内容如下
例如,你有一个带有气泡排序实现的函数C编译器识别这种模式。是否允许编译器将其更改为另一个示例?比如快速排序。 另一个例子是将从0到的所有数字相加,编译器可以用替换for循环。
最近,我无意中编写了如下C代码: 仔细阅读代码,我发现了这个“错误”。然而,在运行时,它没有引起任何问题。明确地说,我的代码是用相对较新版本的MinGW-w64编译的,以创建本机Win32二进制文件。 当然,代码可以工作,但我很惊讶这是允许的,更奇怪的是,我的GCC-ish编译器没有抱怨它!(这个错误有GCC警告选项吗?) 有人能解释为什么这是允许的,以及为什么内部和外部变量不冲突/中断吗?理想情
在这段代码中有一个编译时错误。 "Example.java:17:错误:变量y可能没有被初始化"。 谁能解释一下这个错误的原因以及如何修复它?