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.
Related
I would like to interface with a C library I've written from a C++ program. The C library is written using modern C, and has made use of the static array specifier to show the minimum length of an array, or that a pointer cannot be NULL.
When I try to write a program that interfaces with an extern "C" function using this feature I get the following message:
error: static array size is a C99 feature, not permitted in C++
Is it not possible to interface with this C library? Will I have to modify the C library, or is there an alternative available?
Here's an example program that causes the error:
// foo.h
#ifndef FOO_H
#define FOO_H
void foo(int i[static 1]);
#endif //FOO_H
// foo.c
#include <stdio.h>
void foo(int i[static 1]) {
printf("%i", i[0]);
}
// main.cpp
extern "C"
{
void foo(int i[static 1]);
}
int main() {
int i[] = {1};
foo(i);
}
extern "C" indicates to the C++ compiler that the function name should not be mangled. Since you're linking against an external library, the expectation is that the external library has a function (and only one function) called foo. The static keyword in C99 and onward in an array size tells the compiler that "this array will be at least this size", which may allow the compiler to make certain optimizations (I don't know what optimizations these could be, but consider that it could possibly do loop unrolling up to N = 4, where you declared void foo(int i[static 5]); If you pass an array that is not at LEAST this size, you could have a bad time.
The immediate solution is just that we need to tell the C++ compiler:
There is a function called foo
It takes an int * as a parameter
extern "C"
{
void foo(int i[]);
}
But we lose the information to anyone using this in the C++ program that this function MUST be at least size N (which is what the static keyword in the array size meant). I can't think of a good way to force a compile-time check on this except possibly through some type templated wrapper function:
#include <cstddef>
extern "C"
{
void foo(int i[]);
}
template <std::size_t N>
void c_foo(int i[N])
{
static_assert(N >= 5);
foo(i);
}
int main(int argc, char** argv)
{
int a[5] = {1, 2, 3, 4, 5};
int b[4] = {1, 2, 3, 4};
c_foo<5>(a); // this will be fine
c_foo<4>(b); // this will raise a compile-time error
}
To be extra safe, I'd put the function prototypes for your c_foo functions and any "safe" extern "C" prototypes in one c_library_interface.h file, and the function definitions for your c_foo functions and any "unsafe" extern "C" prototypes in another c_library_interface_unsafe.cpp file. That way, as long as you don't include the unsafe file in your main C++ files, you should only be able to interface with the static array size functions through the templates, which will do some size checking.
(This is additional information to the answer by John)
The C header is not correct in C++ so you will have to modify it .
Probably the intent of [static 1] is to indicate that the function should not be called with a null pointer. There's no standard way to indicate this in both languages and the author's choice is not compatible with C++.
Some major compilers support __attribute__((nonnull)) in both languages, either as a postfix to each parameter, or as a prefix to the function which then applies to all pointer parameters.
In my personalized header I define a preprocessor macro that expands to the equivalent syntax for each compiler , or blank for compilers that don't support it.
Bear in mind that there's no requirement for a compiler to enforce the behaviour and there will certainly be cases where it doesn't (e.g. passing on a received pointer that it doesn't know anything about).
So IMHO with the current state of compiler attitudes towards this feature (be it the attribute or the static 1) , this should be viewed as a form of user documentation.
I actually have decided not to use it in my own code, after some experimentation: using this attribute will cause the compiler to optimize out any null-pointer checks in the function body, which introduces the possibility of runtime errors since there is no effective prevention of null pointers being passed. To make the feature usable, the compiler would also have to issue diagnostics any time the function is called and the compiler cannot guarantee the argument is non-null. (Which is an option I would like to see in compilers, but so far as I know, doesn't exist yet).
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.
I have the following szenario.
I am calling functions in a DLL from a IBM Notes application (Lotusscript).
One of the functions uses type structures and we encounter problems on 64Bit.
All values in the TYPE can only be passed to the function ByRef, but I need to pass the values ByVal.
So I decided to have single arguments in the function header for every value. So far, so good. I have around 43 arguments, but LS can only handle 31 ...
Next idea was to call i.e INIT_REG_PERSON_INFO(arg1,arg2, ... ) before I make a call to the function that registers a new user.
INIT_REG_PERSON_INFO(arg1,arg2, ... );
INIT_REG_ID_INFO(arg1,arg2, ... );
REGISTER_USER();
In C, I have a function ( I know, only one argument, but it is only for testing )
/*====================================================================================*/
/* FUNCTION: BCC_InitRegPersonInfo */
/*====================================================================================*/
STATUS LNPUBLIC BCC_InitRegPersonInfo(char *FirstName){
try {
//extern char *REG_PERSON_INFO_FIRSTNAME;
memset(®_person_info, 0, sizeof (reg_person_info));
reg_person_info.FirstName = FirstName;
return NOERROR;
} catch (...) {
LogEventText("* BCC_InitRegPersonInfo::Exception *", NULLHANDLE, NOERROR);
return 1;
}
}
whre reg_person_info is declared as a global variable
REG_PERSON_INFO reg_person_info;
Later, in my REGISTER_USER(), I try to access the value from the global variable
LogEventText("* BCC_RegNewPerson1():reg_person_info.FirstName = %s", NULLHANDLE, NOERROR,
reg_person_info.FirstName);
But the value is always empty. I assume, the variable is deleted / reset, as soon as I exit INIT_REG_PERSON_INFO(arg1,arg2, ... );
How would I make the value persistent between function calls?
You need to create an external linkage for reg_person_info structure. In this way you are implicitly saying "I want this to be available to all units who declares it, including the main declaration unit".
In the begininning of the file where you have:
STATUS LNPUBLIC BCC_InitRegPersonInfo(char *FirstName){...}
Simply put extern typeOfReg_Person_Info reg_person_info;
by the looks of your code snippet, I am assuming that you have declared reg_person_info somewhere in a header file and #include the header file where you need? I'll update my answer once I have seen more code in the question.
A practice I have seen and used often to share global variables among units is:
/* globals.h */
#ifndef EXTERN
#define EXTERN extern
#endif
EXTERN int gMyGloablVar;
/* some-other-C-file */
#include "globals.h"
/* main.c */
#define EXTERN
#include "globals.h"
In main.c the storage is allocated; in all other compilation units they variables are declared as extern and so are known. In link time the linker fixes all references to the variables in main.
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.
I've been reading questions on Stack Overflow for a few weeks now... this'll be my first question.
So recently I've looked into making C access/manipulate a C++ class. I understand that ideally one shouldn't compile components in C and C++ separately under normal circumstances, but this isn't an option at the moment.
I looked into 3 Tutorials regarding being able to port/use a C++ in C. They are:
"A Guide to C++ and C Interoperability" on DevX
"Mixing C and C++ Code in the Same Program" article on Sun's site.
"[32] How to mix C and C++" on Parashift
First, what I already know:
You must use extern "C" to avoid
C++ function name mangling.
You need callback prototypes that are C-compatible.
G++ must compile the C++ into .o files, GCC compiles the C-specific code into .o files, then link both after.
As a result, the project I have is made of 4 files:
foo.h, header that'll list all prototypes that C/C++ will see (classes invisible to C of course)
foo.cpp containing the Foo class, and a set of C-compatible callback functions to invoke the class and methods.
fooWrap.c a set of C-specific wrappers that reference the callback functions in foo.cpp.
main.c the test method.
Here's the code I typed up, then my questions:
FOO.H
// Header File foo.h
#ifndef FOO_H
#define FOO_H
//Content set inside this #ifdef will be unseen by C compilers
#ifdef __cplusplus
class Foo
{
public:
void setBar(int);
void printBar();
private:
int bar;
};
#endif
//end of C++-only visible components.
#ifdef __cplusplus
extern "C" {
#endif
//Stuff made to be seen by C compilers only. fooWrap.c has definitions.
#if defined(__STDC__) && !defined(__cplusplus)
typedef struct Foo Foo;
//C-wrappers for C++ callback functions.
Foo * c_NewFoo();
void c_SetFooBar( Foo *, int);
void c_PrintFooBar( Foo *);
#endif
//These are the functions C++ AND C can both use...
Foo * newFoo(); //allocates the memory for Foo class, pass address back.
void setFooBar( Foo * , int ); //set internal contents of Foo object.
void printFooBar ( Foo * ); //print internal contents of Foo object.
#ifdef __cplusplus
}
#endif
#endif /*FOO_H*/
TEST.C
#include "foo.h"
// test.c test file for wrappers that manipulate C++ objects.
main()
{
//looks very C++ like... this makes C-Programmers cringe doesn't it?
Foo * cfoo = c_NewFoo();
Foo * cppfoo = newFoo();
//using the C-specific wrappers.
c_SetFooBar(cfoo,31415);
c_PrintFooBar(cfoo);
//using the C/C++ callback functions to Foo objects.
setFooBar(cppfoo,9001);
printFooBar(cppfoo);
}
So I split the definitions up into the 4 files as I mentioned before... and it compiles fine. But here's what I don't quite get.
Why do the sun and parashift articles suggest to create C-Wrappers whose only code is to pass it's arguments onto C/C++ compatible functions who then call C++ specific code?
i.e.
//in Stuff.cpp
void CallCppStuff () { /* c++ stuff */ }
//in wrapStuff.c
wrapCppStuff() { CallCppStuff() }
As you can see from my test.c file... I'm able to call up either set of calls without a problem (as far as I can tell). Are the c_ wrappers needless overhead, or am I missing the whole point of them altogether? My only guess has something to do with pointer addressing schemes of C/C++... but I'm not sure.
Also, I imagine there are more issues beyond just this... but those 3 sites are all I could find specific to this problem. So if there are any other glaring oversights on my part, I'd appreciate their mentioning.
Thanks in advance for any help/advice,
CX
If you have a series of functions that are not object-orientated or in a namespace, there's no need to wrap them again. Your c_ series of functions are redundant.
Any C++ function that is extern C, has global (i.e., not namespace/static member) linkage, and only takes C-compat datatypes (normally we use opaque pointers like you have), then it doesn't need to be wrapped. That is the wrapping function. C++ uses member functions directly and doesn't need to use them, and they certainly don't need to be duped.