So I have looked here and here and at a few other links mentioned in the first question and I have the following code already:
The .cpp file:
#include "arp_piping.h"
#include <string>
#include <iostream>
#include <stdio.h>
std::string exec(char* cmd, FILE* pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
_pclose(pipe);
return result;
}
The header/linker file:
#ifndef ARP_PIPING_H
#define ARP_PIPING_H
#endif
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
my function goes here something like
EXTERNC .....exec(char* cmd, FILE* pipe) ????
#undef EXTERNC
My question is what goes in the bit above as I am unsure what to be typing. I am trying to call the function in the .cpp file from my C main function int main(int argc, char** argv) {}
To call C++ functions from C you need to do two things. 1) Let the C++ code know it's going to be used by C so that it can generate C-friendly symbols. 2) Hide any functionality that C can't understand.
The first part is easily achieved by simply defining the functions as you would in C (I.E. don't use any C++ only features like namespaces) and then wrapping them in an extern "C" block if C++ is defined. You basically want your header file to contain C-only code, and then just open the extern block at the top, and close it at the bottom of the file (my example will make this more clear).
The second part is a little trickier, but not too difficult. In your case, your function returns a std::string which is a C++ only class. It can not be used in C and therefore either needs to be replaced with something that can be used in C, or it needs to be hidden behind something that C can use. For the sake of argument let's assume you can't replace std::string with say, char*. In this case you need to hide std::string from the C-facing code. The common way of doing this is to use an opaque pointer.
Basically, the C-facing code deals only with a pointer to something. That something it neither knows about, nor cares about. The C++ code is free to use a std::string internally, but must make sure to hide it before interfacing with the C API. In my example, you can see I've provided an opaque pointer to a struct I've called cppstring.
In the source file, cppstring is just a struct that holds a std::string. I've changed your example code to use the new cppstring struct. One important thing to note is that because the C code can only deal with a pointer to a cppstring, we need to create it on the heap in our C++ code and return the pointer to it. This means that we must provide the C users some way of freeing it when they're done, which I've also provided in the example.
Using this technique you can wrap the entirety of std::string behind a C API, allowing C users to use all of the functionality that std::string provides. I've provided an example of wrapping std::string::substr to show you how.
N.B. I haven't compiled nor tested this code and for the sake of simplicity I haven't included any of the relevant header files, etc. Nevertheless, it should be enough to get you started.
// C header
#ifdef __cplusplus
extern "C" {
#endif
typedef struct cppstring *cppstring_p;
cppstring_p exec(char *cmd, FILE *pipe);
void free_cppstring(cppstring_p cppstr);
/* example of wrapping std::string::substr for C users */
cppstring_p substr(cppstring_p str, int pos, int count);
#ifdef __cplusplus
}
#endif
// CPP source
struct cppstring {
std::string data;
cppstring(void) {}
cppstring(std::string const& s) : data(s) {}
};
cppstring_p exec(char *cmd, FILE *pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
auto result = new cppstring;
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result->data += buffer;
}
_pclose(pipe);
return result;
}
void free_cppstring(cppstring_p cppstr) {
delete cppstr;
cppstr = nullptr;
}
cppstring_p substr(cppstring_p str, int pos, int count) {
assert(str);
return new cppstring(str->data.substr(pos, count));
}
You need to declare the function as extern "C" in the cpp file:
extern "C" char *exec(char* cmd, FILE* pipe) {
...
}
In the header/linker file you need to declare it's prototype with the keyword "extern", like so:
extern char *exec(char* cmd, FILE* pipe);
Also, are you sure you want to return a c++'s std::string to your C code?
Related
I have a C++ header and cpp files like abc.hpp and abc.cpp which has 2 classes that is class A and class B, am trying to write a C layer containing different methods which calls the C++ layer methods, to call the C++ methods I need to create the instance of Class A and then use this instance to call C++ methods, I have created a C layer but tried different ways to create an instance of class B but it was not possible.
This is ABC.hpp
#ifndef ABC_HPP
#define ABC_HPP
namespace utils {
using std::vector;
using std::string;
class __declspec(dllexport) A
{
protected:
string m_color;
string m_type;
public:
A() {
// TODO: Complete the constructor by intializing everything
m_color = "";
m_type = "";
}
void setColor(string icolor){m_color = icolor;}
void setType(string itype){m_type = itype;}
string getColor(){return m_color;}
string getType() {return m_type;}
virtual ~A() {};
};
class __declspec(dllexport) B
{
// Member Variables
protected:
string file_name;
string place_name;
public:
void setFilename(fname){file_name = fname;}
void setPlaceName(pname){place_name = pname;}
string getFilename(){return file_name;}
string getplaceName() {return place_name;}
void getRes();
};
};
#endif
Similarly we have ABC.cpp
Next I create the C layer xyz_c.h
#ifndef XYZ_H
#define XYZ_H
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) int getPlaceNames(char** oNames);
#ifdef __cplusplus
}
#endif
#endif
Next I create XYZ.cpp
#include "XYZ.h"
#include "ABC.h"
#ifdef __cplusplus
extern "C" {
#endif
int getResults(char** oNames)
{
//here I need to create the instance of B to Call C++ layer getRes()
}
#ifdef __cplusplus
}
#endif
You cannot. C++ was designed to allow it to use the whole set of C legacy code already written, but the other side is not possible... simply because when C was designed there was no C++ available, and C doesn't have constructs as C++ has to be able to link routines written in C.
This means that if you want to combine C and C++ code, the program must be linked as a C++ program (built as) and you can include every routine you want (you can compile individual modules as C modules) but you have to access them from the C++ code including a extern "C" linkage statement in the C++ code (and never the reverse)
C++ has a naming convention for methods and c++ functions that includes information in the name about the types and number of parameters to allow for overloading and to include the object instance in the parameter list. This is simply unknown for a C compiler, so you cannot easily guess the name that the linker uses for something so simple as a void f(void) function (it can be something like 1f4void (yes, starting with a digit) making it impossible to be accessed from C (as C identifiers must start with a letter or underscore). If you declare f as extern "C" f(void), then you can call it from C modules, and it can even be implemented in C (and compiled in c), and the linker will know it as _f (or f is in use today also, depending on the compiler)
You can even write the int main(int argc, char **argv) funtion as a C function, but when you link it, you will need to use the C++ linker, if you want your program to include C++ code.
The proper way to do this is as follows. In your "C" interface code, you should have functions matching the c++ interface with the addition of a void* parameter. This parameter will be used to hold the instance for future usage by XYZ.
SO I would add a abc.c, with definitions as:
void setFilename(void* b, char *fname){
((B*)b)->setFilename(fname);
};
of course you will need to define also creator function such as:
void* CreateB(){
return (void*)new B();
}
In questions such as this, compatibility between C++ classes/structs and C structs is explained as possible as long as all members are of the same type, in the same order, and no virtual members are declared.
That's my problem. I have virtual methods, and I would very much like to keep them when manipulating the struct in C++.
Let's examine this toy example. It's meant to be a C and C++ compatible struct defined in a single header file.
mystr.h:
#ifdef __cplusplus
#include <string>
struct mystr_base {
virtual ~mystr_base() {}
virtual std::string toString() = 0;
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct mystr
#ifdef __cplusplus
: public mystr_base
#endif
{
const char* data;
#ifdef __cplusplus
std::string toString() {
return std::string(data);
}
#endif
};
#ifdef __cplusplus
}
#endif
This may not be exactly pretty, but will do for the example. In a real scenario, the C and C++ variants may be in separate headers, with the C++ struct extending a POD struct. Regardless of implementation, the issue of alignment is still present.
With this example, if a C program was written that passes an instance of mystr to a C++ function, the vtable will interfere with the alignment:
test.h:
#include "mystr.h"
#ifdef __cplusplus
extern "C"
#endif
void mycxxfunc(struct mystr str);
test.cpp:
#include <stdio.h>
#include "test.h"
void mycxxfunc(mystr str) {
printf("mystr: %s\n", str.data);
}
main.c:
#include "test.h"
int main(int argc, char** argv) {
const char* testString = "abc123";
struct mystr str;
str.data = testString;
mycxxfunc(str);
}
$ g++ -c test.cpp && gcc main.c test.o
$ ./a.out
Segmentation fault (core dumped)
(presuming that this is because the C++ function is attempting to read data from beyond the end of the struct's allocated memory)
What's the best way to enable this C-C++ interoperability while still retaining the ability to use virtual functions in C++?
I do not recommend you to clutter your header file with #ifdefs.
The first thing you should do in this case if you want to retain some kind of virtualization and C compatibility at the same time is:
Make your C++ and C type an opaque pointer to the representation.
Put implementation details in a .cpp file.
An idea follows.
Header file:
struct MyStrImpl;
struct MyStr {
MyStrImpl * impl;
};
extern "C" MyReturnType myFunction(MyStr myStr);
Implementation in .cpp file:
struct MyCppString {
virtual ...
};
#ifdef __cplusplus
struct MyStrImpl : public MyCppString {
};
#else
struct MyStrImpl {
};
#endif
MyStr::MyStr() : impl{new MyStrImpl{}} {
}
This way you have a type that can be used from both C and C++.
Advantages:
No #ifdef in header file.
Compatible with C/C++ and consumable from both languages.
Disadvantages:
Lose overloading due to extern "C".
Must use a C-style interface (but can implement with C++-like with virtual functions interface in your .cpp file.
You cannot have both a C-compatible type and virtual functions in a header file at the same time without cluttering it with #ifdef, something that I do not recommend since it can be inconvenient if you need to refactor code.
I have 3 files:
file1.h
#ifndef FILE_H_INCLUDED
#define FILE_H_INCLUDED
#include <stdbool.h> // To prevent unknown type 'bool' error
bool parse(char** &buffer);
#endif
file1.cpp
#include "file1.h"
#include <iostream>
using namespace std;
bool parse(char** &buffer) {
buffer[0] == "test";
}
And file2.cpp includes file1.h and calls parse() with a char **buffer;
When compiling I get:
error: expected ';', ',' or ')' before & token
What am I missing?
EDIT: I'm building a project that uses raw sockets, and it's mostly C code.
You are using a C compiler, not a C++ compiler.
I think what you're really trying to do is to pass an array of char pointers, therefore you could change the function to
bool parse(char** buffer);
The compiler, in C language mode, is complaining about the & symbol:
bool parse(char ** &buffer)
The C language does not allow the & character in that context.
However, it is valid C++ syntax, as the function is requiring a pointer passed by reference.
As others have said, switch to a C++ compiler or tell your compiler to compiler the file as C++ language.
This clue:
bool parse(char** &buffer) {
buffer[0] == "test";
}
Indicates that 'buffer' is to be some sort of reference to some sort of array of strings. Not sure why it is returning a bool (which you overlooked, anyway.)
You should consider:
// a std::vector of std::string
typedef std::vector<std::string> StrVec_t;
// parse can easily add individual std::strings
// to the std::vector (from some unknown source)
bool parse (StrVec_t& buffer)
{
buffer.push_back(std::string("test")); // tbd - where did 'test' come from?
return(true); // and add some meaning to this, or perhaps remove
}
// and is used as
// ...
StrVec_t myWords;
// ...
// ...
(void)parse(myWords); // update myWords from some other source
// ... // example of how to discard bool
I'm running into a mysterious situation with the GCC compiler. So I've got the following files:
//main.cpp
#include "mleak_cpp.h"
int main(int argc, char* argv[])
{
foo();
__memory_malloc(10,"hello",5);
return 0;
}
//mleak_cpp.h
......
void foo(void);
void* __memory_malloc(size_t size, const char* file, int line);
//mleak_cpp.cpp
//definitions of the functions;
void foo(void){printf("foo\n");
void* __memory_malloc(size_t size, const char* file, int line){
printf("%s,%d\n",file,line);
InitDoubleLinkList();
void* p = malloc(size);
if(p == NULL)
return NULL;
__DuLinkList* pListNode;
pListNode = (__DuLinkList*)malloc(sizeof(__DuLinkList));
pListNode->address = p;
pListNode->memorysize = size;
pListNode->file = file;
pListNode->line = line;
InsertBlockToList(pListNode);
return p;
}
For some reason, the call to void foo(void) is fine, but the call to "__memory_malloc" goes down with a linker error, "undefined reference" blah blah. What's the difference between the two functions that causes the different behaviour?
I tried adding "extern C" to the "#include" directive, so main.cpp reads:
extern "C"{
#include "mleak_cpp.h"
}
and adding the keyword "extern" before the declarations of the functions, and this time the call to "foo()" fails too with the same error.
I appreciate any help from you guys
You're placing extern "C" in the wrong place.
If main.c is truly a C file, and mleak_cpp.cpp is truly a C++ function, then you need to put an extern "C" ahead of the definition of __memory_malloc() like so:
extern "C" void* __memory_malloc(size_t size, const char* file, int line){
// ...
}
If you put extern "C" in the mleak_cpp.h file, it needs to be guarded:
#ifdef __cplusplus
extern "C" {
#endif
/* ... body of header ... */
#ifdef __cplusplus
}
#endif
Also, it's not clear why foo works in your example above, when one file calls __foo() but the other file defines foo(). I assume something more is at play, such as an editing error in your question.
extern "C" is for C++, not C, and tells it that the function's name shouldn't be mangled. In C code, you should never see this. Generally, you put it in header files, and you guard it, like this:
#ifdef __cplusplus
extern "C" {
#endif
/* C and C++ compatible header file body here */
#ifdef __cplusplus
} /* end extern "C" */
#endif
If you do it this way though, you need to include the header file in both your C and C++ files, so that the C++ compiler knows to use C linkage.
You can put the extern "C" in front of the function definition in C++ instead and leave it out of the header, but this only works if you only include the headers in C code, so it's recommended to do it the way I pointed out above.
I have looked at other posts and to be honest I am still not sure what is causing the problem. I am programming in Visual Studio and
I have the following code: (this is a C main)
int main(int arc, char **argv) {
struct map mac_ip;
char line[MAX_LINE_LEN];
char *arp_cache = (char*) calloc(20, sizeof(char)); //yes i know the size is wrong - to be changed
char *mac_address = (char*) calloc(17, sizeof(char));
char *ip_address = (char*) calloc(15, sizeof(char));
arp_cache = exec("arp -a", arp_cache);
It uses the following cpp code:
#include "arp_piping.h"
extern "C" char *exec(char* cmd, char* arp_cache, FILE* pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL) {
strcat(arp_cache, buffer);
}
}
_pclose(pipe);
return arp_cache;
}
With the matching header file:
#ifndef ARP_PIPING_H
#define ARP_PIPING_H
#endif
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
#include <stdio.h>
#include <string.h>
extern "C" char *exec(char* cmd, char* arp_cache, FILE* pipe);
#undef EXTERNC
But I keep on getting the following errors:
1>d:\arp_proto\arp_proto\arp_piping.h(14): error C2059: syntax error : 'string'
1>main.c(22): warning C4013: 'exec' undefined; assuming extern returning int
1>main.c(22): warning C4047: '=' : 'char *' differs in levels of indirection from 'int'
Please can I get some help, I have looked at other posts regarding the c2059 but am still getting nowhere
Change your exec declaration to use the EXTERNC macro you have taken pains to define.
EXTERNC char *exec(char* cmd, char* arp_cache, FILE* pipe);
I ran into this compilation error when adding an enum to a project. It turned out that one of the values in the enum definition had a name clash with a preprocessor #define.
The enum looked something like the following:
// my_header.h
enum Type
{
kUnknown,
kValue1,
kValue2
};
And then elsewhere there was a #define with the following:
// ancient_header.h
#define kUnknown L"Unknown"
Then, in a .cpp somewhere else in the project, both of these headers were included:
// some_file.cpp
#include "ancient_header.h"
#include "my_header.h"
// other code below...
Since the name kUnknown was already #define'd, when the compiler came to the kUnknown symbol in my enum, it generated an error since the symbol was already used to define a string. This caused the cryptic syntax error: 'string' that I saw.
This was incredibly confusing since everything appears to be correct in the enum definition and compiles just fine on it's own.
It didn't help that this was in a very large C++ project, and that the #define was being transitively included in a completely separate compilation unit and was written by someone 15 years ago.
Obviously, the right thing to do from here is rename that terrible #define to something less common than kUnknown, but until then, just renaming the enum value to something else works as a fix, e.g.:
// my_header.h
enum Type
{
kSomeOtherSymbolThatIsntDefined,
kValue1,
kValue2
};
Anyway, hopefully this answer is helpful for someone else, since the cause of this error stumped me for a good day and a half.
extern "C" is used to tell the compiler to make it as C grammer, but your mean is to declear a extern function called exec. you just make fusion to the differ of this. so rewrite your code like this in arp_piping.h:
/*extern "C"*/ char *exec(char* cmd, char* arp_cache, FILE* pipe);
and then del the preffix of extern "C" in cpp file.
if you want to comiler them with C grammer, just setting in the cpp which call for the function exec, so write like this:
extern "C" {
#include "arp_piping.h"
}