9
votes

I know adding static member function is fine, but how about an enum definition? No new data members, just it's definition.


A little background:

I need to add a static member function (in a class), that will recognize (the function) the version of an IP address by its string representation. The first thing, that comes to my mind is to declare a enum for IPv4, IPv6 and Unknown and make this enum return code of my function.

But I don't want to break the binary backward compatibility.

And a really bad question (for SO) - is there any source or question here, I can read more about that? I mean - what breaks the binary compatibility and what - does not. Or it depends on many things (like architecture, OS, compiler..)?


EDIT: Regarding the @PeteKirkham 's comment: Okay then, at least - is there a way to test/check for changed ABI or it's better to post new question about that?

EDIT2: I just found a SO Question : Static analysis tool to detect ABI breaks in C++ . I think it's somehow related here and answers the part about tool to check binary compatibility. That's why I relate it here.

2
Probably not, though completely compiler dependent. The C++ standard says nothing about binary object format.Pete Kirkham
Okay then, added gcc tag. I know, that the standard does not say anything about that, but I thought that there could be another standard for this, something related to ABI or something :?Kiril Kirov
@Kiril: the ABI will be defined either by the C++ implementation, or by the vendor of a particular platform, or some combination of the two. It's best to use a platform-specific ABI as far as possible, because then different C++ implementations on the same platform at least have a chance of producing link-compatible binaries. However, some things are always implementation-specific, such as the size and layout of standard library classes, which is why implementations aren't necessarily even link-compatible with themselves (debug vs non-debug) even though following the same C++ ABI.Steve Jessop
... so for a given platform, the C ABI is usually a safer bet than any C++ ABI. It's smaller, and implementations are going to have to follow it for extern "C" stuff if they want to be able to link against the platform's system calls and suchlike.Steve Jessop
@SteveJessop - ah, this confused me more. Do you know any good source, I can read more about that? I'm not familiar with these kind of things at all and obviously, I really need to do something about that :) Thanks!Kiril Kirov

2 Answers

6
votes

The real question here, is obviously WHY make it a class (static) member ?

It seems obvious from the definition that this could perfectly be a free function in its own namespace (and probably header file) or if the use is isolated define in an anonymous namespace within the source file.

Although this could still potentially break ABI, it would really take a funny compiler to do so.

As for ABI breakage:

  • modifying the size of a class: adding data members, unless you manage to stash them into previously unused padding (compiler specific, of course)
  • modifying the alignment of a class: changing data members, there are tricks to artificially inflate the alignment (union) but deflating it requires compiler specific pragmas or attributes and compliant hardware
  • modifying the layout of a vtable: adding a virtual method may change the offsets of previous virtual methods in the vtable. For gcc, the vtable is layed out in the order of declaration, so adding the virtual method at the end works... however it does not work in base classes as vtable layout may be shared with derived classes. Best considered frozen
  • modyfing the signature of a function: the name of the symbol usually depends both on the name of the function itself and the types of its arguments (plus for methods the name of the class and the qualifiers of the method). You can add a top-level const on an argument, it's ignored anyway, and you can normally change the return type (this might entails other problems though). Note that adding a parameter with a default value does break the ABI, defaults are ignored as far as signatures are concerned. Best considered frozen
  • removing any function or class that previously exported symbols (ie, classes with direct or inherited virtual methods)

I may have forgotten one or two points, but that should get you going for a while already.

Example of what an ABI is: the Itanium ABI.

5
votes

Formally... If you link files which were compiled against two different versions of your class, you've violated the one definition rule, which is undefined behavior. Practically... about the only things which break binary compatibilty are adding data members or virtual functions (non-virtual functions are fine), or changing the name or signature of a function, or anything involving base classes. And this seems to be universal—I don't know of a compiler where the rules are different.