1

I want to call a C++ constructor from another language, and need to know what arguments to give it. I think it should be the stated arguments and the "this" pointer. But does the "this" pointer come first or last, in Gnu G++? And are there any other hidden arguments than the "this" pointer?

Other issues such as mangled names are not involved in this question as I already have those issues solved. This question is only about the arguments to a constructor. And the specific language I'm using is not an issue either, as it's a language under development, and this question applies to non-C++ languages in general, not just to a specific language.

Edited to add: This is for an Intel CPU using G++ conventions. That should answer the question of what ABI is involved.

As for "extern C" this is not C++ code. It calls C++ code, but since it's not C++ code itself, it would be meaningless to use "extern C". Also, the C++ code it calls has to be used as-is, without adding stuff to it such as "extern C".

What I'm looking for is not an exact formal definition of calling conventions. I just want some clues to experiment with. Such as, how common is it for C++ compilers to put the "this" pointer at positions other than the first argument? And how common is it for there to be other hidden arguments than the "this" pointer. And if the "this" pointer is not first, is it nearly always last, or is it sometimes in the middle? Etc.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
Mr E
  • 33
  • 6
  • 2
    You will need to look at the specific ABI the C++ code is compiled for. –  Nov 06 '18 at 19:31
  • 2
    There is no specified way to call C++ constructor from another language. For language interoperability, stick to C. – SergeyA Nov 06 '18 at 19:32
  • That's implementation defined. Depends on Compiler. Depends on operating system. Depends on machine architecture. There's no one way to do it. – Jesper Juhl Nov 06 '18 at 19:36
  • @n.m. That's not what the sentence says. It would seem the OP is saying "The external language is not C, and not C++, therefore suggestions of `extern "C"` do not help as that facility/syntax does not exist in the language I'm talking about" – Lightness Races in Orbit Nov 06 '18 at 20:48
  • @LightnessRacesinOrbit maybe you're right, rephrased my answer to take away the ambiguity. Wanted to delete the comment anyway since I wrote an expanded version as an answer. – n. m. could be an AI Nov 06 '18 at 20:54
  • We can't give you "hints" for ABIs, just like we couldn't give you "hints" for C++ syntax, it either is or isn't. C++ ABIs are so horrifying to work with you'd be better off generating C wrappers and working from there. – Passer By Nov 06 '18 at 22:37

3 Answers3

4

Placement of this pointer within the argument list is implementation-defined. If you would like to interact with another language, add a C wrapper:

// Your class
struct MyClass {
    MyClass(int, int);
    void doSomething(char,int);
};
// C wrapper
void* construct_MyClass(int a, int b) {
    return new MyClass(a, b);
}
void doSomething(void* thisPtr, char c, int a) {
    static_cast<MyClass*>(thisPtr)->doSomething(c, a);
}

This way the compiler would take care of placing the parameters in the expected order, leaving your caller code to interact with C APIs. You would need to use extern C in declarations of your C functions to preserve the name for C linkage.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    I feel like your answer ought to mention `extern "C"` and the fact that there's no standardized C++ ABI ... – Jesper Juhl Nov 06 '18 at 19:53
  • @JesperJuhl Nowadays, there are standardized C++ ABIs, and most platforms have chosen one (and *only* one). But those don't nail down the how the standard-library is implemented, so they are of strictly limited use. – Deduplicator Nov 06 '18 at 20:07
  • @Deduplicator So what you are saying is in essence that "there is no standardized C++ ABI".. gotcha. If it's not the same across platforms/compilers/architectures/std lib implementations, then it is *not* a standardized ABI as far as I'm concerned. – Jesper Juhl Nov 06 '18 at 20:11
  • @JesperJuhl No. There is a standard ABI, but it does not encompass the standard-library. In this case, it's sufficient. If you use standard-library-types, it would not be. – Deduplicator Nov 06 '18 at 20:13
  • @Deduplicator If you are thinking of something like the Itanium ABI, then I say that's mostly worthless. I can't use that to link my arm library with a mips library into a x86 executable. *Not* a (useful) standard. – Jesper Juhl Nov 06 '18 at 20:18
  • 1
    @Deduplicator What standard ABI? – Lightness Races in Orbit Nov 06 '18 at 20:50
  • 1
    @JesperJuhl If you want an ABI which crosses all architectures, you need a virtual machine, like for Java or .Net. But that's far afield. – Deduplicator Nov 06 '18 at 21:06
  • "_implementation-defined_" no – curiousguy Nov 16 '18 at 21:54
2

The C++ standard doesn't define how the this pointer and any arguments are passed to a constructor (or any function for that matter). That is the job of the ABI (Application Binary Interface) and different compilers can - and in the real world, do - use different ABIs. The ABI is not part of the C++ standard.

I'm going to assume both languages you want to use are compiled to machine code using a compiler since that makes discussion easier. Similar principles apply to interpreted and other languages, but the specific details differ.

Generally speaking, to correctly call any C++ function from another language, both languages must either be translated to the same ABI by respective language compilers or there must be a defined/documented means by which two different ABIs interoperate. In other words both compilers - and the machine code they generate - must be designed to interoperate.

Practically, the C++ standard specifies how it interoperates with C at the language level. C can't use all C++ constructs, but extern "C" functions are built by a C++ compiler in a way that allows them to be called from C. Compatible C and C++ compilers - or the code they emit - can therefore interoperate, assuming both compilers support the same ABI. For example, g++ (gnu's C++ compiler front end) and gcc (gnu's C compiler front end) are designed to interoperate, but they do not (necessarily) interoperate with compilers from other vendors. Technically, it might be possible for machine code output by a gnu C compiler to interoperate with code output by a C compiler from another vendor, but doing that requires very detailed knowledge of how the ABIs supported by both compilers work (and deliberate support by both vendors).

For other languages to interoperate with C++, the options are less straight-forward. Generally the common denominator is C - other languages provide a facility to interoperate with C, as does C++, so some C interface is used as an intermediary between the two. For example, code that instantiates an object in C++ may be placed in an extern "C" function. That code can then be compiled using a C++ compiler, and the resultant function has an interface that allows calling it from C code. If the other language (or compiler) has support for interoperating with C (i.e. comply with requirements to interface correctly in order to call a C function) then that C function can be called from other languages.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • "Technically, it might be possible for machine code output by a gnu C compiler to interoperate with code output by a C compiler from another vendor" GNU C (and every other C compiler out there) would have a *very* hard time surviving in the marketplace without 100% binary compatibility with native vendor-provided compilers. So if your platform has two C compilers, neither of which is below release 1.0, there are good chances they are binary compatible. There probably are exceptions but I haven't heard of any as of late. – n. m. could be an AI Nov 06 '18 at 21:18
  • @n.m - It's more complicated than that. gcc includes its own C++ ABI, which is distinct from the ABI supported by "native vendor-provided compilers". Before gcc 3.4.0 (from memory) different versions of the gcc ABI were incompatible with each other, which makes it hard to argue they are all compatible with the natively supported ABI. In later gcc versions, the ABIs are forward compatible (i.e. library built with an older version can be linked with a newer version, but not the reverse). – Peter Nov 07 '18 at 09:32
  • I was only talking about C not C++. – n. m. could be an AI Nov 07 '18 at 10:13
0

As for "extern C" this is not C++ code.

C++ code marked extern "C" is C++ code which is callable from C and thus from other non-C++ code. C is kind of lingua franca of inter-language interfaces. If you can talk C, you can talk with anyone who also talks C, which is pretty much everyone in the programming languages world. C ABIs are reasonably straightforward and easy to implement. C++ ABIs, to put it mildly, are anything but (and they are a strict superset of C ABIs so you would have to implement those anyway).

Stick to C-compatible interfaces. You are not the first person in the world who needs to create a C++ object from non-C++ code. Everyone does it via extern "C" code.

the C++ code it calls has to be used as-is, without adding stuff to it such as "extern C".

You don't add anything to existing code in order to interface to it. You write new C++ code, make it call old C++ code, and and mark the new code extern C. The old code is not touched in any way.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Suppose you have an interpreter that wants to invoke C++ code in a dynamic library such as a Linux .so file or a Windows .dll file. Is it better for that interpreter to have built-in ways to adapt to different C++ calling conventions or to generate C++ code for every such call and invoke a C++ compiler for each? – Mr E Nov 06 '18 at 21:15
  • @MrE Something you can implement is 100% better than something you can't, 100% of the time. Do you know of any interpreter that is actually able to do what you propose? – n. m. could be an AI Nov 06 '18 at 21:23
  • Everything that gets done gets done a first time. I'm just trying to reduce the pain of making it work. Being able to adapt to different C++ calling conventions is useful and seems worthwhile to me. But I have to get started by adapting to at least one such calling convention. Which is why I'm asking questions about that convention. – Mr E Nov 06 '18 at 21:33
  • I understand you want to be the first and do it before everybody else does. Outdo Python and get lots of fame and perhaps some money. But then asking other people how to do what you want is not productive. They don't know, by definition. – n. m. could be an AI Nov 06 '18 at 21:35
  • I'm not asking how to adapt. I'm asking what the convention is for the "this" pointer and any other hidden pointers in the call, for the G++ convention on an Intel CPU running Linux or Windows. – Mr E Nov 06 '18 at 21:38
  • If you need to ask , you are not ready to do it. The convention you want is described in the [Itanium ABI document](https://refspecs.linuxfoundation.org/cxxabi-1.86.html). However knowing it, or even being able to implement it perfectly, which is not for the faint of heart, *won't let you achieve your goal*. You may be able to call some C++, maybe 5% to 50% of existing code by my unscientific estimate, but the limit is hard. Some (lots of) C++ code can **only** be called by compiling a C-compatible interface. – n. m. could be an AI Nov 06 '18 at 21:49
  • Let's be realistic. Python has ctypes. It doesn't have c++types. Why? Because nobody needs it? Wrong. Because nobody was ever willing to implement it? Wrong. Because people who tried to implement it were not smart enough? Wrong again. There are lots and lots of extremely bright people who want to extend Python in every possible way, and lots and lots of user who are screaming "shut up and take my money". No c++types. Why? Let it be an exercise for the reader. Do you want to change that? Good luck. There is no right place to ask about this stuff. *You* will be the first place to ask. – n. m. could be an AI Nov 06 '18 at 21:59
  • "_strict superset_" for old traditional C language, not for modern C std – curiousguy Nov 16 '18 at 21:38