C 和 C++ 的结构定义不同——它安全吗? PC-Lint 警告

问题描述 投票:0回答:1

以下声明在 C++ 文件中添加了几个用于编译的运算符。该定义包含在 C 和 C++ 文件中。

PC-Lint 正在报告 Error 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
c++ lint pc-lint
1个回答
7
投票

我假设包含此定义的头文件包含在多个翻译单元中是否正确,其中一些编译为 C++,而另一些编译为普通 C?

如果它是真的,那么你有一个 ODR 违规,根据 C++ 标准,它会调用未定义的行为。

有两种处理方式

  1. 忽略此未定义行为实例,前提是您知道它在您需要支持的平台上的具体表现。 (请注意,未定义的行为 can 表现为一个正常工作的程序)。说实话,对于大多数编译器,你在这里不会有问题。但是,您必须了解此代码是偶然发生的,而不是法律规定的。允许编译器对有成员函数的类使用与没有成员函数的类不同的布局。 (我敢打赌这段代码会在 CINT 上中断,例如)。

  2. 消除未定义的行为。我建议你走这条路。有几种可能性可以做到这一点。例如,您可以从“C Rect”继承“C++ Rect”,将后者保留为普通

    struct
    .

© www.soinside.com 2019 - 2024. All rights reserved.