Structures defined differently for C and C ++ - is it safe? PC-Lint warns

The following declaration adds several statements to compile in a C ++ file. The definition is included in C and C ++ files.

PC-Lint reports error 114: inconsistent structure declaration for the 'Rect' tag, but I'm sure it is safe.

I am compiling with Visual Studio 2008.

edit - adding an explanation that I sent to my client

Regarding the Rect problem; As you know, the structure of the same size in C and C ++ eliminates the suspicion of "undefined behavior".

Undefined behavior occurs if the actual location of the fields in the data structure depends on compilation.

You should think about all access to the member variable, as ultimately to the pointer calculated by the pointer to the beginning of the storage of the object plus the offset depending on what is in this structure.

Packing and data alignment settings affect the offset value.

The compiler is allowed to reorder types for optimal access - undefined behavior assumes that it is only because you declared two members in a specific order that they are actually stored in that order. The only thing that guarantees the declaration order is initialization, copying and destruction order.

However, when you talk about compiling C and C ++ of a given structure within the same compiler, with the same offset settings, the probability of the actual reordering is actually zero.

So the only thing we need to worry about is any difference in field offset.

For a structure containing 4 simple short integers, just confirming that version C and version C ++ are the same size, ensures that their offsets are all the same. To be more careful, we can also check that the size of the structure = 4 * sizeof (short).

I think it’s worth adding these checks, but as soon as this is done, there is no need to reorganize the code, since you will need to use separate types in C and C ++ (or move functions used to free functions).

/** 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 
+4
source share
1 answer

Do I correctly assume that the header file containing this definition is included in several translation units, some of which are compiled as C ++, and some as simple C?

If true, you have an ODR violation that, according to the C ++ standard, causes undefined behavior.

There are two ways to handle this.

  • Ignore this instance of undefined behavior if you know exactly how this manifests itself on the platforms (platforms) that you need to support. (Note that undefined behavior may appear as a properly working program). Honestly, with most compilers you won't have a problem here. However, you must understand that this code works by chance, and not by law. Compilers are allowed to use different layouts for classes with member functions than without them. (I bet that this code will be broken into CINT , for example).

  • Eliminate undefined behavior. I suggest you go this way. There are several ways to do this. For example, you can inherit "C ++ Rect" from "C Rect", saving the latter as a regular struct .

+7
source

Source: https://habr.com/ru/post/1341625/


All Articles