how to call C++ overloaded function from C macros - c++

I'm adding a macro used in C file which should take a variable number of arguments, which should be handled based on the type and the number of arguments differently. If it's pure C++, it's easily achieved by overloading the function, but how would I pass the variadic arguments from C macro into C++ with this mixture of C and C++?
The C file is restricted to be compiled with gcc. In macro definition, I passed the variadic arguments into C wrapper function. Since the number of arguments is unknown, I have a macro counting the arguments and pass it along into va_list. But using this approach, I do not know the type of arguments to flexibly pass any arguments to C++ function. I'm including relevant code snippet reflecting the current structure of code, skipping the actual handling logic in cpp file and other irrelevant information.
In use.c:
#include "macro.h"
LOG(id, lvl, params);
In macro.h:
#define LOG(_MSG_ID_, _LOG_LVL_, ...) \
log_data(&hdr, ##__VA_ARGS__); \
In logger.h:
#define GET_NARG(_1, _2, _3, _4, N, ...) N
#define COUNT_VARARGS(...) GET_NARG(__VA_ARGS__, 4, 3, 2, 1)
#define log_data(p_hdr, ...) \
log_data_c(p_hdr, COUNT_VARARGS(__VA_ARGS__), ##__VA_ARGS__);
#ifdef __cplusplus
class LOGGER
{
public:
void log_data(LOG_HEADER_s* hdr);
void log_data(LOG_HEADER_s* hdr, uint16_t val);
void log_data(LOG_HEADER_s* hdr, uint64_t val);
void log_data(LOG_HEADER_s* hdr, uint32_t val1, uint32_t val1);
// and other overloaded functions
static inline LOGGER& getInstance() { return m_instance; }
private:
static LOGGER m_instance;
};
#else
typedef struct LOGGER LOGGER;
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern void log_data_c(LOG_HEADER_s* hdr, int n, ...);
#ifdef __cplusplus
}
#endif
In logger.cpp:
#include "logger.h"
#include <stdarg.h>
LOGGER LOGGER::m_instance = LOGGER();
#define LOGGER_Instance LOGGER::getInstance()
#ifdef __cplusplus
extern "C" {
#endif
void log_cmn_data(LOG_HEADER_s* hdr, int n, ...)
{
va_list args;
va_start(args, n);
LOGGER_Instance.log_data(va_arg(args, LOG_HEADER_s*));
va_end(args);
}
#ifdef __cplusplus
}
#endif
The ideal scenario would be just passing the variadic arguments in the macro into the invocation of C++ overloaded function. Any workarounds to achieve the result are welcome. I've been trying to get this working for a while but I haven't found a post dealing with the same scenario. Any help is appreciated.

Since the number of arguments is unknown, I have a macro counting the
arguments and pass it along into va_list. But using this approach, I
do not know the type of arguments to flexibly pass any arguments to
C++ function.
That's right, you don't know. The C mechanism for variadic functions does not directly provide the called function any information about the number or types of the variable arguments. The called function must use a combination of assumptions and information gleaned from its arguments to make that determination. The printf function is the canonical example: it determines both the number of variable arguments and their types by analyzing the the provided format string (and havoc ensues if the arguments actually provided are mismatched with the format).
Provided that you place a fixed, artificial upper limit on the number of variable arguments supported, you can indeed count them via a variadic macro, as demonstrated. Very little type information is available to the preprocessor, however, and there is no applicable mechanism for applying what little such information there is to your purpose.
The usual C alternative to function overloading is simply to write functions with different names. If you have similar functions that differ primarily in parameter number and type, then you might give them related names that convey those types. For example,
void log_data(LOG_HEADER_s *);
void log_data_u16(LOG_HEADER_s* hdr, uint16_t);
void log_data_u64(LOG_HEADER_s* hdr, uint64_t);
void log_data_u32_u32(LOG_HEADER_s* hdr, uint32_t, uint32_t);
Alternatively, it might be more appropriate to give them names that convey the purpose of their particular signature. I'm inclined to suspect that an approach along these lines would work better for you than trying to multiplex your several distinct logging functions through a single variadic interface.
On the other hand, if you insist on providing a single variadic function interface, then you could put multiple for-purpose macros in front of it on the C side, each corresponding to one of the supported back-end signatures. These would not need to be variadic (unless the corresponding specific function was). This would be to your advantage because you would get at least argument-count validation from your compiler (for calls going through the macros), and they could provide whatever extra arguments are needed to convey the expected number and types of arguments to the variadic interface function.

Related

Compatibility layer in C++ to access template functions from C

I have some code implemented in template variadic functions that uses modern c++17 features. Being templates, they are implemented in the .h files.
// .H FILE
template <typename... T>
inline constexpr void foo(const T& ...values){
// Do stuff
}
Is there a way to create a compatibility layer that would allow users to access this functions from C?
The way I actually solved may not be valid to all particular cases!!
I found that trying to pass arguments directly to a c++ variadic function was not possible (to the best of my knowledge). Instead, a void vector would be passed, and the results will not be the ones expected. In this case, stringifying the c input, and passing it to the c++ function worked just fine.
#ifdef __cplusplus
extern "C" {
#endif
void cfoo(const char * fmt, ...)
{
va_list args
va_start(args, fmt);
char str[1024];
vsprintf(str, fmt, args);
cpp::foo(str); // My c++ function
va_end(args);
}
#ifdef __cplusplus
}
#endif

How can I implement system-specific functions without macros in modern C++

JetBrains ReSharper for C++ has told me to replace something like
#ifdef _WIN32
# define cls system("cls")
#else // Assuming Unix
# define cls system("tput clear")
#endif // _WIN32
with constexpr template functions.
However, I have tried to use SFINAE via std::enable_if_t<_WIN32>, but I'm getting errors saying "cannot overload functions distinguished by return type alone" (admittedly, I was not using a template function, but instead using enable_if for the return type).
Besides using enable_if as the return type, I don't know how to use constexpr template functions to implement what the preprocessor would do.
In a more general sense, I would like to be able to enable function overloads based on compile-time booleans that don't rely on other template parameters.
Thanks in advance!
You don't want enable_if, which is for cases where you might need to make decisions at compile time based on type parameters, etc.
The preprocessor is appropriate here, though it might be cleaner to use ordinary functions than macros.
#ifdef _WIN32
void cls() { system("cls"); }
#else // Assuming Unix
void cls() { system("tput clear"); }
#endif // _WIN32

Converting empty parameter list function from C to C++

I'm working on a project where I'm trying to compile a VxWorks END in C++. I don't think I'll be able to change working in C++, and I definitely can't change VxWorks too much.
This has gone mostly fine, save for one issue. VxWorks requires all drivers to register their methods with in a net_funcs struct, which has the following fields (among others):
#ifdef __cplusplus
extern "C" {
#endif
...
typedef struct net_funcs
{
...
STATUS (*pollSend) (END_OBJ*, M_BLK_ID); /* Driver's polling send func. */
STATUS (*pollRcv) (END_OBJ*, M_BLK_ID); /* Driver's polling recv func. */
/*
* The minimum required arguments for (*formAddress)() are:
* (*formAddress)(M_BLK_ID, M_BLK_ID, M_BLK_ID, BOOL)
*/
M_BLK_ID (*formAddress) (); /* Driver's addr formation func. */
/*
* The minimum required arguments for (*packetDataGet)() are:
* (*packetDataGet)(M_BLK_ID, LL_HDR_INFO *)
*/
STATUS (*packetDataGet) (); /* Driver's addr formation func. */
...
} NET_FUNCS
...
#ifdef __cplusplus
}
#endif
Note the C-style empty parameter list. In C, this means that this field could be a functor that accepts any argument; however, when compiling in C++, it views these arguments as (void), then throws an error when I attempt to instantiate a struct. If I try to change the arguments to ( first arg, ...), passing in the default lib file calls (endEtherAddressForm and endEtherPacketDataGet, both called from lib file as recommended by the software manual) causes an error because those functors require four specific arguments and don't accept variable numbers of args.
I might be able to just hardcode it to the argument list of the default functions and hope for the best, but before I do, is there any way to make this code work with a variable argument list in both C and C++? Or is there something I have to do to make an extern "C" struct work across two files?
UPDATE:
When instantiating the struct, I use the following code:
LOCAL NET_FUNCS MBbufferNetFuncs =
{
...
MyCode::EndPollSend,
MyCode::EndPollRcv,
endEtherAddressForm, /* Library function from endLib.lib; declaration
M_BLK_ID endEtherAddressForm(M_BLK_ID, M_BLK_ID, M_BLK_ID, BOOL)*/
endEtherPacketDataGet /* Library function from endLib.lib; declaration
STATUS endEtherAddressForm(M_BLK_ID, LL_HDR_INFO *)*/
}
The error states that:
"A value of type "M_BLK_ID (*)(M_BLK_ID, M_BLK_ID, M_BLK_ID, BOOL)" cannot be used to initialize an entry of type "M_BLK_ID (*)()""
Normally, one would think that the extern "C" declaration at the start of the net_func declaration would prevent empty parameter list problems, but this is not the case. I do not know if I need to add special code when I declare my personal copy of the struct, but it does not appear to work.
I'm a bit rusty with C and C++, but if memory serves...
The C syntax for function arguments is:
void foo1(); // Zero or more unspecified args
void foo2(int a, ...); // One or more args
void foo3(void); // No args
The C++ syntax is:
void bar1(...); // Zero or more unspecified args
void bar2(int a, ...); // One or more args
void bar3(); // No args
I can’t test with your setup, but I found (clang -Wpedantic) was happy with:
extern "C" int f(...);
int r(int c) {
return f(c) * c;
}
int main(void) {
return r(2);
}
It even worked, so must not be undefined behaviour... :)
However you need to do something a bit uglier like:
ifdef __cplusplus
#define CLARGS ...
#else
#define CLARGS
#endif
then make your declarations:
M_BLK_ID (*formAddress) (CLARGS);
To prevent C++ from leaking on your C code.

What is the theory and usage behind self including source file in C and C++?

Please refer this FASTLZ.C source code.
At Line #113 and #128 it's including its own source file.
I think it's intention was two defined following functions names with respect to their FASTLZ_LEVEL macro value.
#define FASTLZ_COMPRESSOR fastlz1_compress
#define FASTLZ_DECOMPRESSOR fastlz1_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
#include "fastlz.c"
and
#define FASTLZ_COMPRESSOR fastlz2_compress
#define FASTLZ_DECOMPRESSOR fastlz2_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
#include "fastlz.c"
But I cannot figure it out the theory or key feature behind this Macro in C language, please can someone briefly explain this scenario?
This defines two pairs of functions called fastlz1_compress and fastlz1_decompress, and fastlz2_compress and fastlz2_decompress. The two compress functions are very similar except for a few lines here and there, and similarly for the decompress functions. The self inclusion, which happens twice, is done to remove repetition in the definitions of these two pairs of functions.
Here's an abbreviated version of what the file contains:
#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
...
#undef FASTLZ_LEVEL
#define FASTLZ_LEVEL 1
#undef FASTLZ_COMPRESSOR
#undef FASTLZ_DECOMPRESSOR
#define FASTLZ_COMPRESSOR fastlz1_compress
#define FASTLZ_DECOMPRESSOR fastlz1_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
#include "fastlz.c"
#undef FASTLZ_LEVEL
#define FASTLZ_LEVEL 2
#undef MAX_DISTANCE
#define MAX_DISTANCE 8191
#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
#undef FASTLZ_COMPRESSOR
#undef FASTLZ_DECOMPRESSOR
#define FASTLZ_COMPRESSOR fastlz2_compress
#define FASTLZ_DECOMPRESSOR fastlz2_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
#include "fastlz.c"
...
#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
{
...
#if FASTLZ_LEVEL==2
...
#endif
...
#if FASTLZ_LEVEL==1
...
#else
...
#endif
...
}
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
{
...
#if FASTLZ_LEVEL==2
...
#endif
...
#if FASTLZ_LEVEL==1
...
#else
...
#endif
...
}
#endif
The first part of the file containing the #if block contains a series of macro definitions, but you'll notice that they're defined twice. The second part of the file containing the #else block basically contains a pair of function templates.
The first part defines some macros, then includes itself. On the self-inclusion, the #else part takes effect. This defines fastlz1_compress and fastlz1_decompress based on the FASTLZ_COMPRESSOR and FASTLZ_DECOMPRESSOR macros. Because FASTLZ_LEVEL is set to 1, this activates the fastlz1_compress and fastlz1_decompress specific code.
After the first self-include, these macros are undefined and then redefined for fastlz2_compress and fastlz2_decompress, then the file is self-included again. So the #else part is pulled in again, but this time the effect is fastlz2_compress and fastlz2_decompress are defined, and the code specific to these functions is activated by virtue of FASTLZ_LEVEL now being set to 2.
A slightly less confusing way to do this would have been to put everything between the outer #if and #else in one file and the part between #else and #endif in another file.
A better way would have been to create a single compress function and a single decompress function, with each accepting a parameter to specify the level rather than using macro trickery. For example:
static FASTLZ_INLINE int fastlz_compress(const void* input, int length, void* output, int level)
{
...
if (level==2) {
...
}
...
if (level==1) {
...
} else {
...
}
...
}
Used properly, this can be a useful technique.
Say you have a complex, performance critical subsystem with a fairly small public interface and a lot of non-reusable implementation code. The code runs to several thousand lines, a hundred or so private functions and quite a bit of private data. If you work with non-trivial embedded systems, you probably deal with this situation frequently enough.
Your solution will probably be layered, modular and decoupled and these aspects can be usefully represented and reinforced by coding different parts of the subsystem in different files.
With C, you can lose a lot by doing this. Almost all toolchains provide decent optimisation for a single compilation unit, but are very pessimistic about anything declared extern.
If you put everything into one C source module, you get -
Performance & code size improvements - function calls will be inlined in many cases. Even without inlining, the compiler has opportunities to produce more efficient code.
Link level data & function hiding.
Avoidance of namespace pollution and its corollary - you can use less unwieldy names.
Faster compilation & linkage.
But you also get an unholy mess when it comes to editing this file and you lose the implied modularity. This can be overcome by splitting the source into several files and including these to produce a single compilation unit.
You need to impose some conventions to manage this properly though. These will depend on your toolchain to some extent, but some general pointers are -
Put the public interface in a separate header file - you should be doing this anyway.
Have one main .c file that includes all the subsidiary .c files. This
could also include the code for the public interface.
Use compiler guards to ensure that private headers and source modules
are not included by external compilation units.
All private data & functions should be declared static.
Maintain the conceptual distinction between .c and .h files. This
leverages existing conventions. The difference is that you will have
a lot of static declarations in your headers.
If your toolchain doesn't impose any reason not to, name the private
implementation files as .c and .h. If you use include guards, these
will produce no code and introduce no new names (you may end up with
some empty segments during linkage). The huge advantage is that other
tools (e.g. IDEs) will treat these files appropriately.
In line 27:
#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
you have conditional preprocessor directive, which in line 164 starts it's "else" part, which ends at the end of file. This splits file into two parts: main declaration of general fastlz functions, which is parsed once by compiler, and second part which contains implementation of two functions (FASTLZ_COMPRESSOR and FASTLZ_DECOMPRESSOR).
These two function implementations, which names happen to be a macro definitions, are included twice by first part of file, with some parameters declared (their final names and some other) as macro definitions shortly before inclusion.
This is the C-way of keeping code DRY and don't repeat two almost identical implementations. In C++ (since you've added a C++ tag), you have other mechanisms for the same purpose: inheritance, templates, templates specializations, if constexpr etc.
BTW: mentioned before first if-def line probably contains a bug - it checks if any of the definition was defined, but name of first one "FASTLZ__COMPRESSOR" contains '__' rather than '_' used later. This code fortunately works well, because checked defines are always defined together : ).

declare extern "C" with different return values

I have an function called ecall defined in external ASM file. This function takes different count of arguments and return different values.
This is how it looks like in my source code:
int ret = _function1("Hello", "world");
HANDLER h = _function2(123456);
char * ch = _function3("asdf", 789, h);
// ... and so on
These "functions" are actually macros generated with a simple python script. This auto-generated header file where all these macros are defined looks like:
extern "C" ????? ecall(int code, ...);
#define _function1(...) ecall(0x123, __VA_ARGS__)
#define _function2(...) ecall(0x234, __VA_ARGS__)
#define _function3(...) ecall(0x345, __VA_ARGS__)
#define _function4(...) ecall(0xABC, __VA_ARGS__)
// ... and around 500 more definitions with a different code value
However, I am stuck on the declaration of the ecall (I've marked as "?????"). I need to somehow specify return values, but in fact this function returns pretty much everything (depending on int code value) -- booleans, integers, pointers, etc.
Is there a way how to do this? I am compiling on MSVC10.
Thanks.
Either create your own variant type (a union with each type included), or as I would more strongly suggest, create different functions that each return only one specific type.