0

I want to give a c++ function a custom symbol name (without mangling) so that a can call it from c directly without redirection. For example: If I have the following class in c++:

class Foo {
      public:
        Foo();
        void some_method(int);
        int a_;
      };

I want to give Foo::some_method a custom name like Foo_some_method so that I can call it from c code directly without need for redirection from another function inside extern "C", is that possible?

moamen
  • 169
  • 1
  • 7
  • 5
    How do you expect to call a class member function directly from C code? C... doesn't have classes. What's the left hand side going to be? – Nathan Pierson Sep 25 '21 at 20:51
  • @NathanPierson Yeah c doesn't have classes, but c++ can give a pointer to object to c, then c can call the function directly using the pointer as the first argument. – moamen Sep 25 '21 at 20:54
  • 2
    No it can't, at least not portably. You're just assuming the C and C++ calling conventions are compatible this way. That's a common way of thinking about C++ non-static method calls, but it's an ABI detail, not a guarantee. Just expose an `extern "C"` entry point and do it properly – Useless Sep 25 '21 at 21:04
  • *but c++ can give a pointer to object to c, then c can call the function directly using the pointer* -- Do you have any examples of this being possible? I mean documented, full, working examples from a reputable source? Otherwise, you're just speculating things can be done this way. – PaulMcKenzie Sep 25 '21 at 21:07
  • Give your function a C linkage by declaring it `extern C void Foo_some_method(Foo*)` outside of your class. It cannot be a class member this way, so you need to provide an additional parameter instead of `this`, so the function is called the same way from C and from C++. You probably want to make it a friend of your class. – n. m. could be an AI Sep 25 '21 at 21:17
  • There is no direct way to call a non-static member function of a C++ class from C, since a member function is not a function as C understands it (a call of the form `some_foo.some_method(2)` or `some_foo_ptr->some_method(2)` requires information about both the object (`some_foo` or `some_foo_ptr`) and the member function (`some_method()`) and C functions don't work like that. You can write an `extern "C"` function that (using C++ code in its definition) finds or creates a suitable instance of `Foo`, then calls the member function for that object. – Peter Sep 26 '21 at 02:27
  • @n.1.8e9-where's-my-sharem. It is not possible to have a function callable from C that takes a `Foo *` unless `Foo` is a C `struct` type. Having member functions prevents that. It is possible to pass a `void *` around, and for the function to convert that `void *` to `Foo *` (if the `void *` ACTUALLY points at a `Foo`, and has been returned from other C++ code to the C code). – Peter Sep 26 '21 at 02:31
  • @Peter this is incorrect. The C++ standard does not specify which C++ types are compatible with C ans which are not. Even `void *` does not have to be compatible. It is up to both implementations. In practice `struct Foo*` is likely to work regardless of whether `Foo` itself has any C++-specific guts. Of course one cannot always show the actual definition to C, but a forward declaration is sufficient. – n. m. could be an AI Sep 26 '21 at 05:03
  • Hey y'all, I could make it work! I used asm labels, compiled using gcc and g++, and it worked! – moamen Sep 26 '21 at 20:40

2 Answers2

1

No, to enable a C conpatible calling convention and symbol name you need to produce an extern "C" normal function (in theory, an extern "C" function pointer could also work).

So write your glue code.

It is plausible with reflection you'll be able to automate that. But that is not yet standardized, and covid 19 may delay it past 2023.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

I tested this using g++ and gcc and it worked! I used asm labels to give the symbol a custom name.

product.h

#ifndef BCC702_PRODUTO_H
#define BCC702_PRODUTO_H

#include <string>
#include <ostream>


class product {
public:

    /// Create product
    product(int id, double price, char* name);

    /// Print product
    void print() asm("Asm_product_print");
    void set_name(char* name) asm("Asm_product_set_name") ;

private:
    int id_;
    double price_;
    char* name_;
};

#endif //BCC702_PRODUTO_H

product.cpp compiled to object using g++

#include "product.h"
#include <iostream>

void product::print() {
    std::cout << name_ << std::endl;
}

product::product(int id_, double price_, char* _name_) :
id_(id_), price_(price_), name_(_name_) {}

void product::set_name (char* _name_) {
    product::name_ = _name_;
}

main.c compiled with gcc

typedef struct{
    int id_;
    double price_;
    char* name_;
}  product;
void Asm_product_set_name(product* p, char* string);
void Asm_product_print(product* p);
char* example = "hello world!";
int main(){
    product p;
    Asm_product_set_name(&p, example);
    Asm_product_print(&p);
    return 0;
}

Finally, link objects using g++. And the test result is: Hello world! However, I'm not sure whether it will work with other c++ compilers.

moamen
  • 169
  • 1
  • 7
  • Shouldn't the C standard leading underscore make the symbol names not match? – Yakk - Adam Nevraumont Sep 26 '21 at 22:17
  • So, when a C function is exported, `bob` becomes `_bob` in the symbol table. `asm("foo")` bypasses this, so something called `asm("foo")` should be exported as `foo` not `_foo` to assembly. Above, you use `Asm_product_set_name` as the `asm` name of a function, and below in C you use something whose assembly symbol name should be `_Asm_product_set_name`. How could this work? (I also get that the calling conventions happen to match, which is very compiler specific) – Yakk - Adam Nevraumont Sep 27 '21 at 14:45
  • @Yakk-AdamNevraumont I've tested gcc several times and examined the object file with objdump and I find no leading underscore, I think modern c compilers no longer add a leading underscore to symbols names. – moamen Sep 27 '21 at 18:52
  • Looks like the leading underscore depends on the ABI. https://stackoverflow.com/questions/1034852/adding-leading-underscores-to-assembly-symbols-with-gcc-on-win32 – Yakk - Adam Nevraumont Sep 28 '21 at 01:24