5

I need to have compile time constant in C code:

#define CLASSFROMCXX_SIZE /* compile time constant /*

In C++ code I could just write:

#define CLASSFROMCXX_SIZE sizeof(ClassFromCXX)

But I can't use ClassFromCXX in C code. I could write a function that returns sizeof(ClassFromCXX), but I need compile time constant, not some runtime value.

Is it possible to achieve without code generation? What existing code generation tools could I use to achieve this?

It is more a theoretical question, but as an example: I use some library written in C++ in C code, so I write wrapper in C. I have to store classes from C++ somehow. Related question is: How to call a c++ class and its method from a c file But it uses heap allocation/stack allocation.

  • 4
    Is your end goal to do something like `unsigned char buf[CLASSFROMCXX_SIZE];` following by initializing an object there? – StoryTeller - Unslander Monica Dec 02 '19 at 09:28
  • you could write the function and make it ```constexpr``` – AshleyWilkes Dec 02 '19 at 09:29
  • 5
    @AshleyWilkes Which also won't work well in C. – Some programmer dude Dec 02 '19 at 09:29
  • Yes, I don't want to use any memory allocations there. I have to pass CLASSFROMCXX_ALIGN too. – Barricadenick Dec 02 '19 at 09:29
  • 1
    Please explain more about what you want to achieve by using that constant: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem I ask because sometimes you do not actually need a compile time constant and link time is sufficient. – Yunnosch Dec 02 '19 at 09:30
  • 2
    What is the actual and underlying problem you need to solve? Why do you need the size of the class? Why do you need it as a compile-time constant? Please edit your question to add more details, and if possible ask about your actual problem instead. – Some programmer dude Dec 02 '19 at 09:30
  • I can't use constexpr because there is no constexpr in c code – Barricadenick Dec 02 '19 at 09:30
  • 4
    You can write a small C++ program that generates a C header file with an appropriate `#define`, and make it a part of your build process. – n. m. could be an AI Dec 02 '19 at 09:31
  • It's more a theoretical question, but as an example: I have some library written in C++, and I want to use it in C. To achieve this, I write a wrapper ```unsigned char buf[CLASSFROMCXX_SIZE];``` – Barricadenick Dec 02 '19 at 09:33
  • 13
    If you want to wrap a C++ library in C, then I rather suggest you write another C++ library which exports a C API and uses [opaque data types](https://en.wikipedia.org/wiki/Opaque_data_type) to pass around `void` pointers to the object. – Some programmer dude Dec 02 '19 at 09:35
  • You may try to define size and alignment to fixed values and then, on the C++ side, implement static assertions to check if those values are actually correct. – Giovanni Cerretani Dec 02 '19 at 09:39
  • 1
    Opaque data types are not possible as far as I don't want any memory allocations there. Most classes are small and I need to create/destroy them every step, but every step is fast. – Barricadenick Dec 02 '19 at 09:44
  • 2
    Please, note the alternative declaration `typedef struct some_class some_class;` for C in the accepted answer of [How to call a c++ class and its method from a c file](https://stackoverflow.com/questions/2203023/how-to-call-a-c-class-and-its-method-from-a-c-file). That's an incomplete type. It's size is unknown but it's fine to be used for pointers. So, you have an example for an [opaque data type](https://en.wikipedia.org/wiki/Opaque_data_type) like recommended from @Someprogrammerdude. – Scheff's Cat Dec 02 '19 at 09:44
  • You could write Macros such that if compiled with C++, your code contains a class with data members and methods and if compiled with C it contains a struct containing the same data members. But I think this will end badly in all but the most simple cases (inheritance i.e. has a good chance for killing this). – n314159 Dec 02 '19 at 09:48

2 Answers2

2

You can achieve the goal with Makefile or other compiling tools: compile a piece of C++ code to get the size of the class and assign the size to a macro. After that, you can pass the macro to compile your real code.

Take Makefile as an example:

CODE_TO_GET_SIZE := "\#include \"class_from_cxx.h\"\n\#include <iostream>\nint main() {std::cout << sizeof(ClassFromCXX);}"

CLASSFROMCXX_SIZE := $(shell printf $(CODE_TO_GET_SIZE) | g++ -x c++ - && ./a.out)
for_stack
  • 21,012
  • 4
  • 35
  • 48
  • Yeah, seems to be a good idea. I hope to implement something like this in the future: `#define CLASSFROMCXX_SIZE FROM_CPP_CONSTANT(sizeof(ClassFromCXX))` Then collect all occurrences of FROM_CPP_CONSTANT, compile their argument and print, replace their occurrences with printed values – Barricadenick Dec 02 '19 at 12:06
  • 1
    Wouldn't it be better to add a method to obtain the size to the actual C++-code you are compiling and linking and then call the function from the .o file you are going to use? Because as @MichaelKenzel pointed out, the memory layout can depend on the exact use of your compiler, so the call you have there can in theory produce another size than the object you will link in the end. – n314159 Dec 02 '19 at 13:13
  • Yeah, I have to pass exact the same flags and use the same compiler, but I don't need to use the same .o because if sizeof class would change by some reason, then ABI was broken. – Barricadenick Dec 02 '19 at 13:27
1

What you want is simply not possible. C does not understand C++ class definitions nor C++ object layout. Thus, there is no way a C compiler could compute the size of a C++ class…

I think your best bet here would be to turn the problem around. While C does not understand C++ classes, C++ does understand C structs (to some degree) and can link with C. Instead of a C++ class, define a C struct as well as functions that operate on objects of that type. These functions can be implemented and used across both, C and C++:

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
    int a;
    float p[3];
} SomeThing;

void SomeThing_construct(SomeThing* obj, int arg);
void SomeThing_destruct(SomeThing* obj);

void SomeThing_doYourThing(const SomeThing* obj, float x);

#ifdef __cplusplus
}
#endif

As pointed out by n314159, you could then add a wrapper class around this basic interface to use on the C++ side of things.

I would try to avoid going down the code generation path unless absolutely necessary. For code generation to compute the size of a C++ class means that it has to invoke a C++ compiler at some point. Preferably the exact compiler that will be used to compile the rest of the code with exactly the same flags that will be used to compile the rest of the code (C++ object layout does generally not just depend on the compiler but may even be affected by certain compiler flags). You will want to write a tool that generates a header file that contains the code you need. You will want to integrate the compilation and running of this tool into your buildsystem. Think of the generated header file as a dependency that is to be built like, e.g., a library would be. How you would go about doing this exactly depends on your build system. In a Makefile, you can just add a target to build the header file. If you use CMake to generate your buildsystem, you would add your tool using add_executable, then use add_custom_command() to define how the header file is to be built, and then add the generated header file to the sources of a target…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • I think it would be sensible to write a wrapper class in C++ for this object that manages construction and destruction if used in C++ and can has some methods working on this and so on. – n314159 Dec 02 '19 at 11:06
  • @n314159 thanks for pointing that out. I added a sentence on this to my answer. – Michael Kenzel Dec 02 '19 at 12:59