Using C Headers in C++ - c++

I have searched the googles for this and have found that you use
extern "C" {
#include "header.h"
}
To include a C library inside of a C++ library... however, when I do this. The C++ program seems to pick up all my #defines and struct definitions but none of the function declarations leaving me with undefined reference to `function'.
Here is a minimal amount of src I am using.
json.h
//json.h
typedef struct json_object json_object;
struct json_object {
char key[15][50];
int size;
char value[15][50];
};
void json_parseText(char * text, struct json_object *jo);
test.cpp
//test.cpp
extern "C" {
#include "json.h"
}
int main() {
struct json_object jo;
char * keyVal;
char * text = "{ \"MsgType\": \"article\" }";
json_parseText(text, &jo);
}
g++ yields the following:
test.cpp:(.text+0x2c): undefined reference to `json_parseText'
notice that it is not complaining about the struct definition, so it seems like it got that from the header file. But not the function. This baffles me. I have never used C++ before now, but for my testing framework it must be in C++. Let me know if you have any thoughts on how to fix this. Thanks.

That's a link-time error. In other words, your C++ compiler picked your header all right; you just forgot to link with your library.
Right now, you tell your compiler that such functions and structures exist, but not where it can find them.
For a shared library (.so), you'll have to pass -l[lib name] to G++; you might also have to specify additional folders in the library search path, as -l requires a file name (without the extension) instead of a path. For a static library (.a), you'll have to include its path in the files to compile.

Related

Initialisation of C++ structures from C

I'm trying to use opencv C++ library with another lib in C. So I've defined a structure in an .hpp file which I've added to the .h of the C library
typedef struct {
cv::FileStorage fs;
cv::Mat mat;
} myCPPStruct;
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
myCPPStruct * mycppstruct;
} myCStruct;
void initialize_myCPPStruct(myCPPStruct * mycppstruct);
#ifdef __cplusplus
}
#endif
In the .c files the initializer for myCStruct calls initialize_myCPPStruct which is defined in a .cpp file somewhat as:
void initialize_myCPPStruct(myCPPStruct * mycppstruct){
mycppstruct = {};
mycppstruct->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
mycppstruct->mat = cv::Mat(3,3,CV_8UC3);
}
But once it tries to allocate a value to mycppstruct->fs, it gets a segmentation fault. I assume this is because there is no memory allocation in C, but I've tried
std::memset(stitcher->fs,0,sizeof(cv::FileStorage));
which also doesn't work as it can't parse cv:FileStorage as void *.
Will I have to use the deprecated C OpenCV library to make this work?
EDIT - More details about the compilation.
For the C lib, I recompile (without linking ie with the -c option)all the .c files where I've added C++ functions or structures using g++ while making sure I add the __cplusplus guards in the .h files. All the .c files without C++ code already have .o files compiled with gcc. I then compile the whole program with g++ while making sure to include the relevant library files. There are no compiler errors.
It seems the structure itself has not been created.
You might try this (or something similar):
myCPPStruct* initialize_myCPPStruct()
{
myCPPStruct* result;
result = new myCPPStruct();
result->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
result->mat = cv::Mat(3,3,CV_8UC3);
return (result);
}
You need to allocate the memory for your structure:
myCPPStruct = malloc(sizeof(myCPPStruct));
Use the above line instead of:
mycppstruct = {};
Also,since your function is passing in the pointer and allocating the memory internally you need to pass a pointer to the pointer or the allocation will not be passed back:
void initialize_myCPPStruct(myCPPStruct** mycppstruct){
if ( mycppstruct == NULL ) {
//Abort as no address of the pointer to allocate passed
return;
}
*myCPPStruct = malloc(sizeof(myCPPStruct));
(*mycppstruct)->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
(*mycppstruct)->mat = cv::Mat(3,3,CV_8UC3);
}
Or you could just change the above to:
myCPPStruct* initialize_myCPPStruct(void) {
myCPPStruct* ptr = malloc(sizeof(myCPPStruct));
ptr->fs = cv::FileStorage( "file.txt", cv::FileStorage::READ );
ptr->mat = cv::Mat(3,3,CV_8UC3);
return ptr;
}
First, let me point out the sentence which confuse me.
there is no memory allocation in C
Yes, there is. Have a look to malloc function.
char *my_allocated_string = malloc(sizeof(char) * 42);
Here you are, you've allocated an array of character of size 42.
Now, have a look to : mycppstruct = {};
That's not how you allocate a structure in C. You have to call... malloc() !
my_struct *s = malloc(sizeof(my_struct));
s->fs = 42;
Ok. Done. Feels better.
Well, first of all, you have to create a wrapper around your C++ code. Why ? Because C++ allows multiple definition of a given function (also call symbol) :
int my_func(int);
int my_func(char);
This is valid in C++. But, think about it, how is the compiler able to let two functions with the same name exist ? Well it's not. It uses a technique named mangling when evaluating the functions to create 2 different names. Mangling is use on everything function and method. Event on single functions.
C is not able (and willing) to create several functions with the same name. Otherwise, you will experience a kind of function-already-implemented error. When you declare :
int my_func(int);
the C compiler will create the symbol : my_func. No mangling.
To make both language interact, you need to reference to a symbol understandable by the C compiler. If you call my_func from a C source file, the C compiler will look for my_func symbol. Bu since C++ will modify its my_func symbol into something like _ZN9myfuncE, the linkage will fail. That's why you have to says to the C++ compiler to not use mangling on the function you expose to C. That's why you need extern "C" { }.
Feeww, so far so good...
Now you have to embed you C API into an extern "C" block :
In my_c_api.h :
void my_func(int);
void my_func(char);
In my_c_api.cpp :
#include "my_c_api.h"
extern "C" void my_func_i(int i) { my_func(i); }
extern "C" void my_func_c(char c) { my_func(c); }
You compile it to create your C++ library.
In your C compilation pipeline, you link against your new C++ library and header files. Then :
#include "<path_to_my_c_api.h>"
void c(int i,char s)
{
my_func_i(i);
my_func_c(c);
}
You cannot compile C++ code with C compiler. You have to compile te C++ code independently.
More on ISO CPP.

creating c++ object in c file

I have a query for creating c++ object inside c file.
I have the sample code below. When trying to import the CPlusHeader it throws an error which i could not understand.
The error is iostream' file not found as one of the error. How could i resolve this issue.
Regards,
Lenin
CPlusFile.h
include iostream
include string
using namespace std;
class CPlusFile {
int data;
public:
CPlusFile();
int getData();
};
CPlusFile.cpp
CPlusFIle::CPlusFIle() {
data = 10;
}
int CPlusFile::getData() {
return data;
}
CFile.h
int doSomething();
CFile.c
include "CFile.h"
include "CPlusFile.h"
int doSomething() {
CPlusFile object;
}
It strongly depends on what you call a "C file". Previous answer assumed that you meant a file with a .c suffix. I assume here that you mean a file that shall be compiled with a C compiler.
If my assumption is valid, then the answer is simple: You cannot instantiate C++ classes in a C file. What you can do, though, is call C++ static methods from the C code. Please refer, for example, to In C++ source, what is the effect of extern "C"? to see how to do this.
First of all, it is
#include <iostream>
#include <string>
and not
include iostream
include string
Second, if CFile.c is compiled as C, then this will not work. The C compiler will not understand the class keyword and you cannot create an instance of a class in C.
iostream is a C++ header, and isn't available if you're compiling using a C compiler. You can write C++ code in a .c file, you just need to use the right compiler.
You can use this in your C++ header file to check wether you are going to include it from C or C++ code:
#ifdef __cplusplus
The includes iostream and others, as well as using class, are only available for C++ code.
But if you want to use the CPlusFile class, which is a C++ class, you can only do that in C++ code. Best is to rename your CFile.c to CFile.cpp.
Yes, it is possible to call C++ object inside the C file. Here I performed a scenario and
it's working fine for me.
CPlusFile.h
#include<iostream>
#include<string>
using namespace std;
class cplus{
int data;
public:
cplus();
int getdata();
};
CPlusFile.cpp
#include "cplusfile.h"
cplus::cplus(){ data =10; }
int cplus::getdata(){ return data; }
CFile.h
#include "cplusfile.h"
#include<stdio.h>
int dosomething();
CFile.c
#include "cfile.h"
int dosomething(){
cplus c;
printf("%d",c.getdata());
}
int main() {
dosomething();
return 0;
}
And compile this by g++ CFile.c CPlusFile.cpp and it works fine.

C++ undefined reference to defined function

I cannot figure out why this is not working. I will put up all three of my files and possibly someone can tell me why it is throwing this error. I am using g++ to compile the program.
Program:
#include <iostream>
#include "h8.h"
using namespace std;
int main()
{
char sentence[MAX_SENTENCE_LENGTH];
char writeTo[] = "output.txt";
int distanceTo,likePosition, length, numWords;
cout << "ENTER A SENTENCE! ";
cin.getline(sentence, 299);
length = strlen(sentence);
numWords = wordCount(sentence, length);
for(int x = 0; x < 3; ++x)
{
likePosition = likePos(numWords);
distanceTo = lengthTo(sentence, likePosition, length);
insertLike(sentence, distanceTo, length, writeTo);
}
return 0;
}
Function file:
void insertLike(const char sentence[], const int lengthTo, const int length, char writeTo[])
{
char part1[MAX_SENTENCE_LENGTH], part2[MAX_SENTENCE_LENGTH];
char like[] = " like ";
for(int y = 0; y < lengthTo; ++y)
part1[y] = sentence[y];
for(int z = lengthTo+1; z < length - lengthTo; ++z)
part2[z] = sentence[z];
strcat(part1, like);
strcat(part1, part2);
writeToFile(sentence, writeTo);
return;
}
Header file:
void insertLike(const char sentence[], const int lengthTo, const int length, const char writeTo[]);
The error exactly is:
undefined reference to 'insertLike(char const*, int, int, char const*)'
collect2: ld returned 1 exit status
The declaration and definition of insertLike are different
In your header file:
void insertLike(const char sentence[], const int lengthTo, const int length, const char writeTo[]);
In your 'function file':
void insertLike(const char sentence[], const int lengthTo, const int length,char writeTo[]);
C++ allows function overloading, where you can have multiple functions/methods with the same name, as long as they have different arguments. The argument types are part of the function's signature.
In this case, insertLike which takes const char* as its fourth parameter and insertLike which takes char * as its fourth parameter are different functions.
Though previous posters covered your particular error, you can get 'Undefined reference' linker errors when attempting to compile C code with g++, if you don't tell the compiler to use C linkage.
For example you should do this in your C header files:
extern "C" {
...
void myfunc(int param);
...
}
To make 'myfunc' available in C++ programs.
If you still also want to use this from C, wrap the extern "C" { and } in #ifdef __cplusplus preprocessor conditionals, like
#ifdef __cplusplus
extern "C" {
#endif
This way, the extern block will just be “skipped” when using a C compiler.
You need to compile and link all your source files together:
g++ main.c function_file.c
This could also happen if you are using CMake. If you have created a new class and you want to instantiate it, at the constructor call you will receive this error -even when the header and the cpp files are correct- if you have not modified CMakeLists.txt accordingly.
With CMake, every time you create a new class, before using it the header, the cpp files and any other compilable files (like Qt ui files) must be added to CMakeLists.txt and then re-run cmake . where CMakeLists.txt is stored.
For example, in this CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8.11)
project(yourProject)
file(GLOB ImageFeatureDetector_SRC *.h *.cpp)
### Add your new files here ###
add_executable(yourProject YourNewClass.h YourNewClass.cpp otherNewFile.ui})
target_link_libraries(imagefeaturedetector ${SomeLibs})
If you are using the command file(GLOB yourProject_SRC *.h *.cpp) then you just need to re-run cmake . without modifying CMakeLists.txt.
If you are including a library which depends on another library, then the order of inclusion is also important:
g++ -o MyApp MyMain.o -lMyLib1 -lMyLib2
In this case, it is okay if MyLib1 depends on MyLib2.
However, if there reverse is true, you will get undefined references.
As Paul said, this can be a linker complaint, rather than a compiler error. If you read your build output/logs carefully (may need to look in a separate IDE window to see the full details) you can dell if the problem is from the compiler (needs to be fixed in code) or from the linker (and need to be fixed in the make/cmake/project level to include a missing lib).

undefined reference to the shared library function

I have implemented a shared library in Linux and try to test it, but I get an error "undefined reference to `CEDD(char*)'".
I use Eclipse with following parameters:
Path to include files (here is
everything ok)
Path to the library
and its name. Path is correct and the
name is WISE_C (full name:
libWISE_C.so)
My Code:
Test programm I use for tests:
#include <iostream>
#include <Descriptor.h>
int main() {
char* path = "/export/home/pdmazubi3/workspace/proj1/src/pic.jpg";
double * cedd = CEDD(path); ///// <-ERROR!
std::cout << "!!!Hello World!!!" << cedd[1];
return 0;
}
Header Descriptor.h:
double* CEDD(char* path);
A part of Descriptor.c with desirable function:
#include "Descriptor.h"
#include "highgui.h"
#include "cv.h"
double* CEDD(char* path)
{
IplImage* srcImg;
IplImage* ImageGrid;
...
}
What I am doing wrog? I have raed a lot of articles in the Internet but I didn't found a solution.
undefined reference to `CEDD(char*)' is a compiler or linker error?
It's a linker error (although I don't think it usually includes the 'char*' bit), so it seems that it either cannot find your library or the library does not contain the function. The latter might also mean that it does contain the actual function, but with a different name; make sure both projects a compiled as C and not C++.
Edit: I missed that you program is C++ (which also explains the more detailed linker message). In this case you should add extern "C" (conditionally, so it is only used when using C++) to the declaration of CEDD if the library is in C.
Are you sure that you linked the object code generated for descriptor.c when building?

How to use 2 C libs that export the same function names [duplicate]

This question already has answers here:
Closed 13 years ago.
Duplicate of the following question: C function conflict
Hi,
in my current project I have to use some kind of interface lib. The function names are given by this interface, what this functions do is developers choice. As far as I can tell a project shall use this functions and when it comes to compiling you choose the lib and with it the functionality. What I try to do is to use an existing lib and my lib at the same time by wrapping the other and call it in mein functions:
otherlib:
int function1 (int a) {
// do something
}
mylib:
int function1 (int a) {
//my code here
otherlib::function1(a);
}
Problem is I don't have access to the other lib and the other lib doesn't have any namespaces. I already tried
namespace old {
#include "otherlib.h"
}
and then call the old function by old::function1 in my function. This works as long as it's only header file. The lib exports it's symbol back into global space. Also something like
namespace new {
function1 (int a) {
::function1(a);
}
}
didn't work. Last but not least I tried ifdefs and defines suggested here
but I wasn't successful.
Any ideas how to solve this? Thanks in advance.
EDIT: I neither have access to the old lib nor the project both libs shall be used in.
EDIT2: at least the old lib is a static one
Namespaces in C solved using library names prefixes like:
libfoo --> foo_function1
libbar --> bar_function1
These prefixes are actual namespaces. so if you write libbar
int bar_function1(int a) {
function1(a);
}
This is the way to solve problems.
C has namespaces --- they just called prefixes ;)
Another option is to do various dirty tricks with dynamic loading of libraries like:
h1=dlopen("libfoo.so")
foo_function1=dlsym(h1,"function1")
h2=dlopen("libbar.so")
bar_function1=dlsym(h2,"function1")
It seems as if the other lib is C and your code is C++. You can be running into a mangling problem (C++ compilers mangle the symbols -- add extra stuff in the symbol name do differentiate overloads and the like).
If the library is pure C you can try:
extern "C" { // disable mangling of symbol names in the block
#include "otherlib.h"
}
namespace new_lib { // new is a reserved word
int function1( int a ) {
::function1(a);
}
}
I have not tried it. Also consider providing the error messages you are getting.
Another option would be (if the library is dynamic) dynamically loading the lib and calling the function. In linux (I don't know about windows) you can use dlopen to open the library, dlsym to obtain the symbol and call it:
// off the top of my head, not tried:
int function1( int a )
{
int (*f)(int); // define the function pointer
void * handle = dlopen( "library.so" );
f = dlsym( handle, "function1" );
f( a ); // calls function1(a) in the dynamic library
}
In this case, as you are not linking against the library you won't get a symbol conflict, but then again, it is only valid for dynamic libraries and it is quite cumbersome for regular usage.
UPDATE
If your users will not use 'otherlib' directly (they won't include their headers) and they will be only C++, then the first approach could be possible (even if horrible to read):
// newlib.h
namespace hideout {
int f( int a );
}
using namespace hideout; // usually I would not put this on the header
// newlib.cpp
extern "C" { // if otherlib is C, else remove this line
#include "otherlib.h"
}
namespace hideout {
int f( int a ) { return ::f( a*2 ); }
}
// main.cpp
#include "newlib.h"
int main()
{
std::cout << f( 5 ) << std::endl;
}
How does it work? User code will only see a declaration of function1 (in the example f()) as they are not including otherlib.h. Inside your compilation unit you see the two declarations but you differentiate through the use of the namespace. The using statement in the header does not bother you as you are fully qualifying in your cpp. The user main.cpp will include only your header, so the compiler will only see hideout::f, and will see it anywhere due to the using statement. The linker will have no problem as the C++ symbol is mangled identifying the real namespace:
// g++ 4.0 in macosx:
00002dbe T __ZN7hideout9function1Ei // namespace hideout, function1 takes int, returns int
00002db0 T _function1
If user code will include both your header and otherlib.h then it will have to qualify which function it wants to call.
If you're really desperate, you could write a wrapper library that uses namespaces or prefixes or allows for the dlsym trick. This wrapper library would need to be dynamically linked (to avoid symbol conflicts). The dynamic library could then safely have the old static library embedded in it. Just make sure you don't export the symbols from the static library when making the dynamic wrapper library.
You can't resolve this at link time, so you'll need to resolve it at runtime via dynamic libraries. The symbol for those functions is essentially baked it once the library has been generated. If two libraries export the same symbol, they cannot both be linked with statically.