Calling zlib (C code) from a C++ file - c++

I have a .cpp file that contains the following function to decompress a file via zlib:
#include <zlib.h>
#include <fstream>
bool gzip_uncompress(std::string &compressed_file_path,std::string &uncompressed_file_path)
{
char outbuffer[1024*16];
gzFile infile = (gzFile)gzopen(compressed_file_path, "rb");
FILE *outfile = fopen(uncompressed_file_path, "wb");
gzrewind(infile);
while(!gzeof(infile))
{
int len = gzread(infile, outbuffer, sizeof(outbuffer));
fwrite(outbuffer, 1, len, outfile);
}
fclose(outfile);
gzclose(infile);
return true;
}
This looks like it should run to me, but I'm getting compile time errors stating:
No matching function call to 'gzopen'
and
No matching function call to 'fopen'
The only thing I can thing of is that I am calling these in a C++ file, and the zlib is a C library. I'm not sure about the fopen error though.
Does anyone see how I can call these functions and get around the compile error?
I hava also tried:
extern "C" {
#include <zlib.h>
}
but still no go. Am I barking up the wrong tree? Should I move this function into a C file? But then I'd presumable have the same issue.

Use .c_str() when passing a std::string to functions that expect a char *.

there are two things here...
Compile time inclusion of C header in C++ file
Linking C compiled lib (zlib) with C++ program
for the first issue, your compiler is not able to see declaration of gzopen, there might be many reasons for that..
please check the declaration of functions gzopen in zlib.h
Make sure you need to include path to zlib.h in the arguments to g++
ex: -I/usr/local/include/zlib.h
Please follow the link below for developer documentation
http://www.zlib.net/manual.html
Please follow the help
For 2. Linking your C++ program with zlib, please use
extern "C" {
#include <zlib.h>
}

Related

error when using extern "C" to include a header in c++ program

I am working on a school project which requires to work with sheepdog. Sheepdog provides a c api which enables you to connect to a sheepdog server.
First i create c source file(test.c) with the following content :
#include "sheepdog/sheepdog.h"
#include <stdio.h>
int main()
{
struct sd_cluster *c = sd_connect("192.168.1.104:7000");
if (!c) {
fprintf(stderr, "failed to connect %m\n");
return -1;
}else{
fprintf(stderr, "connected successfully %m\n");
}
return 0;
}
then i compile with no error using the following command
gcc -o test test.c -lsheepdog -lpthread
But what i need is to use it with c++ project so i created a cpp file(test.cpp) with the following content :
extern "C"{
#include "sheepdog/sheepdog.h"
}
#include <stdio.h>
int main()
{
struct sd_cluster *c = sd_connect("192.168.1.104:7000");
if (!c) {
fprintf(stderr, "failed to connect %m\n");
return -1;
}else{
fprintf(stderr, "connected successfully %m\n");
}
return 0;
}
now, when i compiled using the following command :
g++ -o test test.cpp -lsheepdog -lpthread
I got this error :
You can't just wrap extern "C" around a header and expect it to compile in a C++ program. For example, the header sheepdog_proto.h uses an argument named new; that's a keyword in C++, so there's no way that will compile as C++. The library was not designed to be called from C++.
I agree with #PeteBecker. From a quick look around Google, I am not sure there is an easy solution. Sheepdog is using C features and names that don't port well to C++. You might need to hack sheepdog fairly extensively. For example:
move the inline functions out of sheepdog_proto.h into a new C file, leaving prototypes in their place. This should take care of the offsetof errors, e.g., discussed in this answer.
#define new not_a_keyword_new in sheepdog/sheepdog.h
and whatever other specific changes you have to make to get it to compile. More advice from the experts here.
As sheepdog was not designed to be useable from C++ you should build a tiny wrapper in C language to call the functions from sheepdog and only call the wrapper from your c++ code. Some hints to write such a wrapper:
void * is great to pass opaque pointers
extractors can help to access badly named members. If a struct has a member called new (of type T), you could write:
T getNew(void *otherstruct); // declaration in .h
and
T getNew(void *otherstruct) { // implementation in a c file
return ((ActualStruct *) otherstruct)->new;
}
Depending on the complexity of sheepdog (I do not know it) and the part you want to use, it may or not be an acceptable solution. But it is the way I would try facing such a problem.
Anyway, the linker allows mixing modules compiled in C and in C++, either in static linking or dynamic linking.

How to distinguish files of two separate programs with common file

I've project where I need to distinguish files belongs to linux daemon (witten in C) and simple linux program (written in C++). Those two projects used 2 shared files (helpers_functions). Daemon and program has different logging system. Daemon write to file, program to stdout.
Problem occurs when I want to log something in common functions for both programs (inside helper_functions file). I don't want to pass via parameter, that this is program A, or program B.
I've compile files belongs to separate programs with g++ flag -D, but what can I do, when I want to log from common files? I cannot define there anything, because I don't know when I use it for program A, or when for program B.
You could add a global variable
const int iamprogram = ...;
which is defined to be PROGRAM_A in program A and PROGRAM_B in program B to solve the immediate problem. You could also make this variable directly contain the file you want to log to:
const char *program_logfile = "/path/to/logfileA";
In the long run, I suggest you to refactor your code such that the common code doesn't depend on which program it is part of. That's much more maintainable and expandable for the case where you want to use the code for a third program as well.
I'm not 100% sure if runtime dynamic linking can handle this. It would definitely work if you statically link the helper functions into each executable.
Provide a logging function with the same API in both programs. Have the library functions that want to log something call this function. They get the implementation provided by the program that's using the library.
Header file included by each program, and by the library
// common_log.h
#ifdef __cplusplus
extern "C" // for the following definition only, no opening {
#endif
// used by code that can be part of either program
void common_log(char *msg, int log_prio);
Implementation in the tty C++ program (simple logging):
#include "common_log.h"
#include <iostream>
// used by the rest of the C++ program
void simple_logger(char *msg) {
cerr << msg;
}
extern "C" void common_log(char *msg, int log_prio) {
simple_logger(msg);
}
Implementation in the daemon C program:
#include "common_log.h"
#include <stdio.h>
#include <errno.h>
static FILE *logfp;
static int log_level;
// used by daemon code
void fancy_logger(char *msg, int log_prio) {
if (log_prio < log_level)
return;
if (EOF == fputs(logfp, msg)) {
perror("failed to write log message to log file: ");
}
}
// or use linker tricks to make common_log an alias for fancy_log,
// if they both have the same signature and you don't need to do anything in the wrapper.
//extern "C" // this is already C
void common_log(char *msg, int log_prio) {
fancy_logger(msg, log_prio);
}
This requires the linker to be able to resolve undefined symbols in the library using symbols from the program that's linked against it. I think that works, similar to a library providing a weak definition of a global variable, so the main program's definition takes precedence.
If it was ok for simple_logger to also be extern "C" and have the same signature, you could just name them the same and avoid the bounce function. Or if the common function could be an alias for the program's own logging function in either of the programs, I think there are linker tricks to actually do that, instead of compiling to a single jmp instruction (tail-call optimization).
You could implement a callback for getting the program specific output. There's two benefits: no dependency from common part to application (common part defines the interface) and you can make the distinction at run time vs compile time, which gives more legroom for future development, such as changing the output via command line parameters or user interaction.
In the following example, let's refer to the common code part as "library".
library.h
typedef void (*logFunc_t)( logBuffer_t );
void setLogOutput( logFunc_t applicationLog );
library.c
logFunc_t logger; // might be good idea to initialize to an empty function, but omitted here
void setLogOutput( logFunc_t applicationLog )
{
logger = applicationLog;
}
void log( logBuffer_t data )
{
logger( data );
}
application.cpp / application.c
// here you should have the extern "C" in C++ application to ensure linkage compatibility
// I am assuming your shared code is C
extern "C" void myLogger( logBuffer_t data );
int main( int argc, char* agv[] )
{
setLogOutput( &myLogger );
// ...do your thing
return 0;
}
void myLogger( logBuffer_t data )
{
// ...log wherever
}

Using C Headers in 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.

How do I load a shared object in C++?

I have a shared object (a so - the Linux equivalent of a Windows dll) that I'd like to import and use with my test code.
I'm sure it's not this simple ;) but this is the sort of thing I'd like to do..
#include "headerforClassFromBlah.h"
int main()
{
load( "blah.so" );
ClassFromBlah a;
a.DoSomething();
}
I assume that this is a really basic question but I can't find anything that jumps out at me searching the web.
There are two ways of loading shared objects in C++
For either of these methods you would always need the header file for the object you want to use. The header will contain the definitions of the classes or objects you want to use in your code.
Statically:
#include "blah.h"
int main()
{
ClassFromBlah a;
a.DoSomething();
}
gcc yourfile.cpp -lblah
Dynamically (In Linux):
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen ("libm.so", RTLD_LAZY);
if (!handle) {
fprintf (stderr, "%s\n", dlerror());
exit(1);
}
dlerror(); /* Clear any existing error */
cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}
printf ("%f\n", (*cosine)(2.0));
dlclose(handle);
return 0;
}
*Stolen from dlopen Linux man page
The process under windows or any other platform is the same, just replace dlopen with the platforms version of dynamic symbol searching.
For the dynamic method to work, all symbols you want to import/export must have extern'd C linkage.
There are some words Here about when to use static and when to use dynamic linking.
It depends on the platform. To do it at runtime, on Linux, you use dlopen, on windows, you use LoadLibrary.
To do it at compile time, on windows you export the function name using dllexport and dllimport. On linux, gcc exports all public symbols so you can just link to it normally and call the function. In both cases, typically this requires you to have the name of the symbol in a header file that you then #include, then you link to the library using the facilities of your compiler.
You need to #include any headers associated with the shared library to get the declrarations of things like ClassFromBlah. You then need to link against the the .so - exactly how you do this depends on your compiler and general instalation, but for g++ something like:
g++ myfile.cpp -lblah
will probably work.
It is -l that link the archive file like libblah.a or if you add -PIC to gcc you will get a 'shared Object' file libblah.so (it is the linker that builds it).
I had a SUN once and have build this types of files.
The files can have a revision number that must be exact or higher (The code can have changed due to a bug). but the call with parameters must be the same like the output.

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?