2

I've got two modules. One calls other one and passes as an argument a structure.

struct {
    char* szDGRTag;
    bool bTagEx;
} ADPTAG;

Master is written in C++ from '98 in Visual C++ 6.0. Slave is written in C++ 11 in Visual Studio 2010 Professional.
Function that is called in Slave:

long lCheckPresenceOfFields (char* szName, ADPTAG* AdpTagList, long lNbVar)

In Master:

long lNbVar = 2;
ADPTAG* AdpTagList = NULL;
AdpTagList = new ADPTAG[lNbVar];

AdpTagList[0].szTag = new char[32];
AdpTagList[0].bTagEx = true;
memset(AdpTagList[0].szTag, 0x0, 32+1);
AdpTagList[0].szTag = NULL;

AdpTagList[1].szTag = new char[32]; 
AdpTagList[1].bTagEx = true;
memset(AdpTagList[1].szTag, 0x0, 32+1);
AdpTagList[1].szTag = NULL;

int size = sizeof(AdpTagList[0]);
AdpTagList[0].szTag = "DDD";
AdpTagList[1].szTag = "AAA";

long pres = pGetFieldsPresence(szPath, AdpTagList, 2);

I've checked size of AdpTagList[0] in Master and it was 5 bytes, but in Slave it is 8 bytes, so the first object is OK, but any next is bad, because pointer points to wrong memory area.
What can be the issue here? Different compilator? Probably not as structure with only char* and int works fine between these two modules.
Regardlesss of size of 1st object [0], second [1] is null-pointer.

Marek
  • 1,189
  • 3
  • 13
  • 33

2 Answers2

3

You're running into a packing discrepancy. You can modify the packing with the "/Zp" compiler option.

Since by default Visual Studio:

Packs structures on 8-byte boundaries

It's very likely that your Visual Studio 2010 compiler does not specify packing. Your Visual C++ 6.0 application likely did specify 1-byte packing as a structure containing an int and a char should pack into that.

Using 1-byte packing optimizes a programs system memory footprint, because no memory is lost to padding.

Using 8-byte packing optimizes speed because it increases the chance that structures can be fetched in a single load.

For more on packing you can read here: https://msdn.microsoft.com/en-us/library/71kf49f1.aspx

But I'd go with Microsoft's statement:

You should not use this option unless you have specific alignment requirements

Meaning since you have to change one, I'd recommend changing the packing on the Visual C++ 6.0 application.

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • Slave module will be used with many Masters. So I assume that best option would be to use char* and int which compiles to 8 bytes, with no padding. It will be compatibile for Masters with 1, 2, 4 or 8 byt Struct Member Alignment. Yet may be not for 16, but I can assume that there will not be no such a case. What do you think? – Marek Jun 23 '16 at 12:10
  • @MarekCzaplicki I've edited, but my preference is to fix the alignments in Visual C++ 6.0. You can always buy more ram if you're worried about memory footprint. You can never buy more time. – Jonathan Mee Jun 23 '16 at 12:21
  • Yeah, but this would mean for me that every other Master module must be checked about this padding. – Marek Jun 23 '16 at 12:30
  • @MarekCzaplicki My warning would be that you need to get these using the same padding, I've suggested that you go with Microsoft's 8-byte recommendation for the sake of speed. But if you decide to use 1-byte packing that is a viable option. Gaming the struct to try to force it to be 8-byte is a very bad option. You'd run into problems again if a zealous compiler recognized that you only needed 6-bytes to address all of your program's memory space and adjusted pointer size. This would result in a 14-byte struct which would again be misaligned. – Jonathan Mee Jun 23 '16 at 12:42
  • 1
    Okay, I get it now. You are right. In this case I will probably stick with boolean instaed of integer. And set Struct Align to 8 bytes as MS standard in every Master module. – Marek Jun 23 '16 at 13:00
  • 1
    Although the answer makes sense, and appears to be correct in this case, I feel compelled to note that the default packing even back in VC++ 6 was 8 bytes. So someone had to have changed that setting to 1 byte. Which was a poor decision, the speed improvement for properly aligned values has vastly outstripped the space savings since *at least* the 386 processor. It might make more of a difference if you're building giant arrays of objects in memory, but that's one of those "Doctor, it hurts when I do this"..."Well then stop doing it" things. – Cody Gray - on strike Jun 24 '16 at 04:57
  • @CodyGray Thanks, I didn't check the default on Visual C++ 6.0. It's important to hear that someone has added some weak sauce to the project settings. I think that we are all in agreement here that what needs to change is the Visual C++ 6.0 app needs to be set to 8 byte packing. – Jonathan Mee Jun 24 '16 at 12:29
2

Yes, its the compiler difference that's to blame. There is no standardisation at all of C++ at the binary level. In particular this means any compiler is free to choose its own padding rules for structures, which is what is affecting you here. Clearly the more recent compiler has decided to add 3 bytes of padding to make the structure 64-bit aligned, but the older compiler doesn't do this.

In general there is no way to ensure binary compatibility between data produced by two different compilers. You can either switch to using byte streams, or use the same compiler for both.

Smeeheey
  • 9,906
  • 23
  • 39