下面的声明为C文件中的编译添加了几个运算符。C和C文件中都包含了这个定义。
PC-Lint报告 * 错误114:标记“Rect”* 的结构声明不一致,但我确信它是安全的。
我正在用Visual Studio 2008编译。
编辑-添加我发送给客户的说明
- 关于Rect问题;知道C和C++中的结构体大小相同,如何消除对“未定义行为”的怀疑?*
如果字段在数据结构中的实际位置随编译而变化,则会发生未定义的行为。
您必须将所有成员变量访问视为最终解析为一个指针,通过指向对象存储开头的指针加上偏移量(取决于该结构中的内容)来计算。
打包和数据对齐设置会影响偏移量的值。
编译器可以重新排序类型以获得最佳访问--假设仅仅因为你以给定的顺序声明了两个成员,它们实际上就以该顺序存储,这是未定义的行为。声明顺序唯一保证的是初始化、复制和销毁顺序。
但是,当您讨论在同一个编译器中使用相同的偏移量设置对给定结构进行C和C编译时,实际重新排序的机会实际上为零。
因此,我们唯一需要担心的是场偏移的任何差异。
对于一个包含简单的4个短整型的结构体,只需确认C版本和C版本的大小相同,就可以保证它们的偏移量都相同。为了更仔细,我们还可以检查结构体size = 4*sizeof(short)。
我认为添加这些检查是值得的,但是一旦完成了这些检查,就没有必要像在C和C++中使用单独的类型那样重构代码(或者将正在使用的函数移到自由函数中)。
/**
Mac-compatible rectangle type with some operators added for C++ use.
@ingroup QuickdrawPort
*/
struct Rect {
short top;
short left;
short bottom;
short right;
#ifdef __cplusplus
Rect(short _top=0, short _left=0, short _bottom=0, short _right=0) :
top(_top),
left(_left),
bottom(_bottom),
right(_right)
{}
#ifdef _WINNT_ // WinDef.h has been included
const Rect& operator=(const tagRECT& rhs) {
top = short(rhs.top);
left = short(rhs.left);
bottom = short(rhs.bottom);
right = short(rhs.right);
return *this;
}
operator tagRECT() const {
tagRECT lhs;
lhs.top = top;
lhs.left = left;
lhs.bottom = bottom;
lhs.right = right;
return lhs;
}
#endif// _WINNT_
short height() const { return bottom - top; }
short width() const { return right - left; }
bool empty() const { return right==left || bottom==top; }
bool operator==(const Rect& rhs) const {
return top == rhs.top &&
left == rhs.left &&
bottom == rhs.bottom &&
right == rhs.right;
}
#endif
};
#ifndef __cplusplus
typedef struct Rect Rect;
#endif
1条答案
按热度按时间waxmsbnn1#
我假设包含这个定义的头文件包含在几个翻译单元中,其中一些被编译为C++,而另一些被编译为普通C,这样的假设是否正确?
如果为true,则存在ODR冲突,根据C标准,该冲突将调用未定义的行为。
有两种方法来处理它。
1.忽略此未定义行为的示例,前提是您知道它在平台上的确切表现方式(s)你需要支持。(注意,未定义的行为 * 可以 * 表现为一个正确工作的程序)。说实话,对于大多数编译器来说,你在这里不会遇到问题。但是,你必须明白,这段代码是偶然工作的,编译器被允许对有成员函数的类和没有成员函数的类使用不同的布局(例如,我敢打赌这段代码在CINT上会崩溃)。
1.消除未定义的行为。我建议你这样做。有几种可能性可以做到这一点。例如,你可以从“C Rect”继承“C Rect”,保持后者为一个普通的
struct
。