Using C Code in C++ Project - c++

I want to use this C code in my C++ project :
mysql.c :
/* Simple C program that connects to MySQL Database server*/
#include <mysql.h>
#include <stdio.h>
#include <string.h>
main() {
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
char *server = "localhost";
char *user = "root";
char *password = "rebourne"; /* set me first */
char *database = "mydb";
conn = mysql_init(NULL);
/* Connect to database */
if (!mysql_real_connect(conn, server,
user, password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
/* send SQL query */
if (mysql_query(conn, "show tables")) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_use_result(conn);
/* output table name */
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(res)) != NULL)
printf("%s \n", row[0]);
/* close connection */
mysql_free_result(res);
mysql_close(conn);
}
it compiles with gcc :
gcc -o output-file $(mysql_config --cflags) mysql.c $(mysql_config --libs)
but not with g++ ..
What would you do ?
edit :
The Error is :
exit(1); was not declared in this Scope

First things first: it would probably be a lot more helpful if you showed us the compilation errors.
That being said, my initial instinct is to suggest:
extern "C"
{
#include <mysql.h>
#include <stdio.h>
#include <string.h>
}
This is a guess right now, but without the actual error messages it's the best you're going to get.
Oh, and perhaps renaming the file to end in .cpp, .c++ or .C (uppercase) would help.

use :
extern "C"
{
YOUR CODE HERE
}

OK, now that the answer is given there are a few lessons to learn.
First, always provide the errors when you're reporting things that don't compile. Those messages contain valuable information. Don't paraphrase them either. Cut and paste them in their own code block.
Second, any time you use a function, check the docs. I have never seen C documentation that didn't tell you the required header file up at the top of the man page or equivalent. It's as much a part of the documentation as explaining what the function does. There is a myriad of headers required in programming C and C++. Documenting the required headers for functions is a very common documentation idiom as a result.

#include <stdlib.h>
Though I doubt that it has really said "exit(1);". Please show exact messages next time.

Now, I haven't programmed C in a long while (and was never at a very high level) but I find it odd that you would want to include a main() function into an already existing code base. Is it really the compiler, or the linker, that's complaining? And when you say that GCC succeeds in compiling the code, are you only compiling that one source file, or including it in a bigger code base as well?
If my guess is correct, it would make sense for you to rename the function to something other than main, e.g. connect_to_database().

Related

Getting error message MSB6006 error code 2 with C/C++

I'm getting the following message trying to compile some simple code: MSB6006 "CL.exe" exited with code 2.
I'm trying to learn C++. I know some C. I understand the two are completely different languages. I include both tags because I get different results depending on how I try to compile the code.
For my own education, I'm trying to write a lexer. Mainly the problem seems to be with this function:
word scan(char** source)
{
word w;
w.lexeme[0] = '\0';
return w;
}
I get the same problem as this one MSB6006: "CL.exe" exited with code 2 but the answer doesn't apply in my case. I saw this question error MSB6006: "CL.exe" exited with code 2 which pointed to this question on the MSDN site They seem to indicate that small problems can cause this error code.
I have two files. One is a "driver" and the other is the lexer code. But I get the exact same results if I include everything in one file.
Here is the code for the driver:
#include "pch.h"
#include "Cl2aDLL.h"
void Cl2a(char argv1[], char argv2[])
{
char** source = NULL;
scan(source);
}
Here is the code for the header. I got the technique somewhere from a MSFT website:
#pragma once
#ifndef CL2ADLL__H__
#define CL2ADLL__H__
typedef struct {
char* lexeme;
}word;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CL2ADLL_EXPORTS
#define CL2ADLL_API __declspec(dllexport)
#else
#define CL2ADLL_API __declspec(dllimport)
#endif
CL2ADLL_API void Cl2a(char argv1[], char argv2[]);
word scan(char** source);
#ifdef __cplusplus
}
#endif
#endif // ! CL2ADLL__H__
Here is the code for the lexer:
// Error MSB6006 "CL.exe" exited with code 2.
#include "pch.h"
#include "Cl2aDLL.h"
/*
// when I comment out the following lines, it compiles and runs okay
word scan(char** source)
{
word w;
w.lexeme[0] = '\0';
return w;
}
*/
// if I only have the following, I get compile error if .cpp
word scan(char** source)
{
}
The strange thing is that if I compile as C code it compiles and runs okay. But if I try to compile as C++ I get the error message. If I uncomment out the first version of the scanner, I get the error message compiling as C or C++ either one.
Does anyone know of a change that can remove this error message?
Sorry for the long question, but I'm trying to give as clear a definition of the problem as I can. Because I can't figure out what could be wrong. TIA.
Update: I'm using VS 2019 Community Edition 16.1.1
Update 2: I got the same results with version 16.1.2. But trying the code in VS2017 Community Edition 15.9.12 showed the problem, as shown below.
Also I should have explained that all the above code was in a .dll file. The .dll code was run from a simple console application as follows:
#include "..\CL2aDLL\CL2aDLL.h"
int main(int argc, char* argv[])
{
char parm1[1 + 1] = "";
char parm2[1 + 1] = "";
if (argc == 1) {
Cl2aDLL(parm1, parm2);
}
else {
Cl2aDLL(argv[1], argv[2]);
}
return 0;
}
I've done some additional research.
Running the code in VS Community Edition 15.9.12 showed that the line w.lexeme[0] = '\0'; was trying to use an uninitialized pointer.
The corrected function is:
word scan(char** source)
{
word w;
w.lexeme = (char*)malloc(1); // <-- line added
w.lexeme[0] = '\0';
return w;
}
This compiles and runs okay.
However that still doesn't explain why this code gives the MSB6006 error:
word scan(char** source)
{
}
And this only happens when compiling as C++. It compiles and runs okay if compiling as C.
Update: I reported the problem to MSFT but it doesn't look liked they fixed the problem yet.

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.

Local dynamic library

Right off the bat, I want to say that I've never worked with dynamic libraries so It's possible that I don't even understand how they work properly.
I want to have a fully loaded code running and after some trigger (probably user interaction) I want to load a specific library and execute a function inside that library. Preferably close it afterwards. Essentially allowing me to change it and re-load it during run time.
This is the simple dynamic library (called dynlib.so located in the same directory as the main code):
int getInt(int arg_0)
{
return (arg_0 + 7);
}
And this is the main program:
#include <iostream>
#include <dlfcn.h>
int main() {
void *lib_handle = dlopen("./dynlib.so", RTLD_LAZY | RTLD_NOW);
if (!lib_handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
typedef int (*func_ptr)(int);
func_ptr func = (func_ptr)dlsym(lib_handle, "getInt");
std::cout << func(13);
dlclose(lib_handle);
}
I'm compiling it using: g++ -std=c++11 -ldl loadlibtest.cpp -o main.
The error I'm catching is ./libshared.so: file too short In my if (!lib_handle) {.
It works fine for me. I've compiled dynlib.so with
$ gcc dynlib.c -fPIC -shared -o dynlib.so
(Obviously, you need to either compile it as C or C++ with extern "C" to avoid name mangling).
and I needed to place -ldl after the source file in the g++ invocation.
gcc: 4.8.5; g++: 5.3.0
dlsym may fail too and casting from void* to function pointers is technically UB. You should base it on the usage snippet from the
manpage(modified for your function):
dlerror(); /* Clear any existing error */
/* Writing: func = (int (*)(int)) dlsym(handle, "getInt");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&func) = dlsym(handle, "getInt");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
After some great replies I discovered what I'm doing wrong.
1) I wasn't using extern "C" for my library functions, so dlsym was unable to find the function.
2) I didn't know that dynamic libraries had to be compiled << pretty stupid of me.
I still want to know if there is a way to use uncompiled code as a library, but my initial problem was solved, thanks to everyone.

ibmemcached Linking Error: undefined reference to `memcached_exist'

I am trying to write a sample code using libmemcached c/c++ client version (0.53)
gcc -o test test.c -I/home/libmemcached/include -L/home/libmemcached/lib -lmemcached -lmemcachedutil
However i get an error
/tmp/ccoaToYP.o: In function main':
test.c:(.text+0x255): undefined reference tomemcached_exist'
Has anyone come across this issue ? I cannot use version higher than 0.53 (basically any 1.0) due to limitation with installed gcc. I see that this command was added for 0.53.
Also, The path and ld_library_path are straightforward too.
PATH is set with /bin:/sbin:/usr/bin:/usr/sbin:/usr/bin/X11:/usr/sbin.
LD_LIBRARY_PATH is set with /home/libmemcached/lib:/usr/lib:/usr/lib64:/lib
$ nm libmemcached.so | grep -i memcached_exist
00014bc2 T _Z15memcached_existP12memcached_stPKcj
00014b06 T _Z22memcached_exist_by_keyP12memcached_stPKcjS2_j
$
If i comment out the memcached_exist call, rest of code compiles and executes just fine.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libmemcached/memcached.h>
int main(int argc, char *argv[])
{
memcached_server_st *servers = NULL;
memcached_st *memc;
memcached_return rc;
char *key= "keystring";
char *value= "keyvalue";
uint32_t flags;
char return_key[MEMCACHED_MAX_KEY];
size_t return_key_length;
char *return_value;
size_t return_value_length;
memc= memcached_create(NULL);
servers= memcached_server_list_append(servers, "localhost", 11211, &rc);
rc= memcached_server_push(memc, servers);
if (rc == MEMCACHED_SUCCESS)
fprintf(stderr,"Added server successfully\n");
else
fprintf(stderr,"Couldn't add server: %s\n",memcached_strerror(memc, rc));
rc= memcached_set(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0);
if (rc == MEMCACHED_SUCCESS)
fprintf(stderr,"Key stored successfully\n");
else
fprintf(stderr,"Couldn't store key: %s\n",memcached_strerror(memc, rc));
return_value= memcached_get(memc, key, strlen(key), &return_value_length, &flags, &rc);
if (rc == MEMCACHED_SUCCESS)
{
fprintf(stderr,"Key %s returned %s\n",key, return_value);
}
rc = memcached_exist(memc, key, strlen(key));
fprintf(stderr," Error Code: %s\n",memcached_strerror(memc, rc));
return 0;
}
Thanks
Antony
If you don't want to compile as C++, you can always call the mangled name directly. If you want this code to be reusable and to be able to upgrade the libraries easily, etc, you shouldn't do that. For a more extensible solution, I'll add to H2CO3's answer.
If you want to for some reason keep all your main source compiled as C, you can create a .cpp file that has stubs that call the C++ library functions. For example:
// libraries.cpp
//
// (includes needed to memcached lib call and types)
extern "C" memcached_return memcached_exist(memcached_st *memc, char *key, size_t len)
{
return memcached_exist(memc, key, len);
}
Then you can compile libraries.cpp and link against the memcached libs using g++ to a libraries.o and link against that on your gcc line.
Name mangling. The shared object file contains mangled C++ function (method?) names, while your code is compiled as C, containing the non-mangled name memcached_exist. Try compiling your file as C++.

How to log with pantheios to a file?

I tried the exemple from pantheios to log to a file but can't manage to make it work.
Messages are correctly displayed in the console but the log file isn't created.
I tried to change severity levels since I saw that thread, but no one works.
Here's the code :
/* Pantheios Header Files */
#include <pantheios/pantheios.hpp> // Pantheios C++ main header
#include <pantheios/inserters/args.hpp> // for pantheios::args
#include <pantheios/inserters/exception.hpp> // for pantheios::exception
#include <pantheios/backends/bec.file.h> // be.file header
/* Standard C/C++ Header Files */
#include <exception> // for std::exception
#include <new> // for std::bad_alloc
#include <string> // for std::string
#include <stdlib.h> // for exit codes
/* ////////////////////////////////////////////////////////////////////// */
/* Define the stock front-end process identity, so that it links when using
* fe.N, fe.simple, etc. */
PANTHEIOS_EXTERN_C const PAN_CHAR_T PANTHEIOS_FE_PROCESS_IDENTITY[] = PANTHEIOS_LITERAL_STRING("example.cpp.file");
/* ////////////////////////////////////////////////////////////////////// */
#define PSTR(x) PANTHEIOS_LITERAL_STRING(x)
/* ////////////////////////////////////////////////////////////////////// */
int main(int argc, char **argv)
{
try
{
#ifndef PANTHEIOS_USE_WIDE_STRINGS
pantheios::log_DEBUG("main(", pantheios::args(argc, argv), ")");
#else /* ? !PANTHEIOS_USE_WIDE_STRINGS */
STLSOFT_SUPPRESS_UNUSED(argc); STLSOFT_SUPPRESS_UNUSED(argv);
#endif /* !PANTHEIOS_USE_WIDE_STRINGS */
pantheios::log_NOTICE(PSTR("stmt 1"));
// Set the file name for the local back-end, truncating the
// file's existing contents, if any.
pantheios_be_file_setFilePath(PSTR("log.local"), PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BEID_LOCAL);
pantheios::log_NOTICE(PSTR("stmt 2"));
// Set the file name for the remote back-end.
pantheios_be_file_setFilePath(PSTR("log.remote"), PANTHEIOS_BEID_REMOTE);
pantheios::log_NOTICE(PSTR("stmt 3"));
// Set the file name for all back-ends.
pantheios_be_file_setFilePath(PSTR("log.all"));
pantheios::log_NOTICE(PSTR("stmt 4"));
pantheios::log_DEBUG(PSTR("exiting main()"));
system("pause");
return EXIT_SUCCESS;
}
catch(std::bad_alloc&)
{
pantheios::log(pantheios::alert, PSTR("out of memory"));
}
catch(std::exception& x)
{
pantheios::log_CRITICAL(PSTR("Exception: "), pantheios::exception(x));
}
catch(...)
{
pantheios::logputs(pantheios::emergency, PSTR("Unexpected unknown error"));
}
return EXIT_FAILURE;
}
/* ///////////////////////////// end of file //////////////////////////// */
I have an "include_pantheios.cpp" file for implicit link purpose. Here it is :
/* Pantheios Header Files */
#include <pantheios/implicit_link/core.h>
#include <pantheios/implicit_link/fe.simple.h>
#include <platformstl/platformstl.h>
#include <pantheios/implicit_link/be.file.h>
#if ( defined(UNIX) || \
defined(unix))&& \
( defined(_WIN32) || \
defined(_WIN64))
# include <unixem/implicit_link.h>
#endif /* _WIN32 || _WIN64 */
Does somebody see where my problem come from?
Thanks in advance,
Vincent
I think part of your confusion comes from the example doing too much: it shows local and remote files all in one. A simpler example would be:
// Headers for main()
#include <pantheios/pantheios.hpp>
#include <pantheios/backends/bec.file.h>
// Headers for implicit linking
#include <pantheios/implicit_link/core.h>
#include <pantheios/implicit_link/fe.simple.h>
#include <pantheios/implicit_link/be.file.h>
int main() {
pantheios::log_NOTICE("log-1"); // save until log file set
pantheios_be_file_setFilePath("mylogfile"); // sets log file; write "log-1" stmt
pantheios::log_NOTICE("log-2"); // write "log-2" stmt
pantheios_be_file_setFilePath(NULL); // close "mylogfile"
pantheios::log_NOTICE("log-3"); // save until log file set
pantheios_be_file_setFilePath("mylogfile2"); // sets log file; write "log-3" stmt
pantheios::log_NOTICE("log-4"); // write "log-4" stmt
} // closes "mylogfile2" during program closedown
The problem with the original code, which I think comes from a Pantheios example program, is that it's trying to illustraet how to use local and remote back-ends at the same time as trying to illusteate how to use the be.file backend.
Forget all the different back-ends, and concentrate on the be.file-specific stuff.
HTH
I got the same problem, for future people, the problem is the order to link libraries
Pantheios Forum :
https://sourceforge.net/projects/pantheios/forums/forum/475314/topic/5313841/index/page/1
I just link the pantheios.1.be.file.gcc44 before the pantheios.1.be.fprintf.gcc44
I think the issue is the order in which you link, but I don't quite see how it's possible given the code you posted.
I encountered the same issue, and I realized that it was because I was linking two backends at once: file and fprintf. More specifically, it was because I was linking fprintf before file. When I switched the order to link file first, then it would create and use the log file, but would not output to stdout when I commented out pantheios_be_file_setFilePath. So apparently whichever is linked first is the only one that will work (look up multiple backends).
As far as I can tell this code is identical to the file stock back-end sample given with the library, so it ought to work.
How are you determining that the log files are not written? These are relative paths - try using absolute paths to be sure you are looking in the correct place.
If all else fails, you could debug through the code (after the filepath is set) to find out why nothing is getting written out.