我正在尝试使用gdb.The编译标志调试C程序,我使用的标记如下所示
-fno-strict-aliasing -Wall -DHAVE_CONFIG_H -DNO_OLD_ERF_TYPES -Werror -Wredundant-decls -O2 -DNDEBUG -DBYTESWAP -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -g 我使用的编译器的版本是
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.有争议的代码如下所示
spm->num_streams = (uint16_t)((MkIV->stream_counts >> 16 ) & 0xfff);num_streams with -fno-strict-aliasing值
0xffff (4095)num_streams WITHOUT-fno-strict-aliasing值
0x1 (1)值得注意的是,mkIV->stream_counts is 0x10020.This的实际值是从HARDWARE REGISTER读取的。
我们感兴趣的值是spm->num_streams是BIT27:BIT16.Therefore,期望值是'1'
如果我要取代
spm->num_streams = (uint16_t)((MkIV->stream_counts >> 16 ) & 0xfff);使用
spm->num_streams = (uint16_t)((MkIV->stream_counts & 0xfff0000) >> 16);然后,我得到了0x1(1)的值和不含-fno-strict-aliasing的值。
stream_counts in MkIV结构(MkIV->stream_counts是uint32_t type)
spm->num_streams is of type uint16_t有人能解释一下为什么会这样吗?
发布于 2013-09-24 02:05:25
由于使用stream_counts对volatile进行了限定,所以您似乎受到了as-if规则的影响,该规则基本上说,如果编译器能够修改程序,只要它能够确定它不会影响可观察到的行为。Cp偏好在这里有一个很好的解释,尽管它是针对C++编写的,但大多数也适用于C。这些代码示例特别有指导意义。
与C++标准草案不同的是,C99标准草案只明确提到索引中指向第3段中的5.1.2.3程序执行的“如果”规则,它说(强调“我的”):
在抽象机器中,所有表达式都由语义指定。一个实际的实现不需要计算表达式的一部分,如果它可以推断它的值没有被使用,并且没有产生所需要的副作用(包括调用函数或访问易失性对象所引起的任何副作用)。
它确实在一些例子中使用了好象短语,从第11段中我们有以下例子:
float f1, f2;
double d;
/* ... */
f1 = f2 * d;下面的案文是(强调我的):
如果实现可以确定结果与使用双精度算法执行的相同,则可以使用单精度算法执行乘法。
如果我们看一看6.7.3类型限定符部分,第6段说(强调我的):
具有易失性限定类型的对象可以以实现未知的方式进行修改,或者具有其他未知的副作用。因此,引用这样一个对象的任何表达式都应严格按照5.1.2.3中描述的抽象机器的规则进行计算。此外,在每个序列点上,最后存储在对象中的值应与抽象机器规定的值一致,除非前面提到的未知因素对其进行了修改。
这就限制了编译器对volatile限定对象可以采取的快捷方式。5.1.2.3第5段涵盖了对符合实现的最小要求。
发布于 2013-09-24 00:25:26
你是“以假乱真”规则的受害者。编译器不知道您是从硬件寄存器中读取的。当你写:
spm->num_streams = (uint16_t)((MkIV->stream_counts & 0xfff0000) >> 16);编译器完全有权这样做:
uint16_t j = MkIV->stream_counts;
MkIV->stream_counts &= 0xfff0000;
MkIV->stream_counts >>= 16;
sp->num_streams = MKIV->stream_counts;
MkIV->stream_counts = j;最有可能的是,您可以通过使stream_counts易挥发或通过易失性指针“清洗”读取来解决这个问题。
不要使用MkIV->stream_counts,而是使用*(volatile uint16_t *)&MkIV->stream_counts。
https://stackoverflow.com/questions/18970921
复制相似问题