I was trying to override a C-style function (func) in a library with a C++ style function accepting different arguments, as the code below demonstrates.
I compiled test.cpp into a shared library libtest.so, and compiled main.cpp and linked it with the libtest.so library. This all works, upto the linking step, where I get
undefined reference to 'func(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'.
Can someone explain me why the linker cannot resolve the C++ function? I checked with nm that both functions are indeed in the library. The linker error occurs both with intel and g++ compilers.
test.h:
extern "C" {
int func( char* str, int size );
}
#include <string>
int func( std::string str );
test.cpp:
#include <stdio.h>
#include <string>
#include "test.h"
int func( char *buf, int size )
{
return snprintf( buf, size, "c-style func" );
}
int func( std::string& str )
{
str = "c++-style func";
return str.size();
}
main.cpp:
#include <iostream>
#include <string>
#include "test.h"
int main()
{
char buf[1024];
func( buf, 1024 );
std::cout << buf << "\n";
std::string str;
func( str );
std::cout << str << "\n";
}
You've declared the function in test.h as int func(std::string), but defined it in test.cpp as int func(std::string &). See the difference?
Related
I am making something in c++, it doesn't have any errors visible in Visual Studio code, but when I use g++ to be able to execute it, I get this error:
In file included from Main.cpp:6: In file included from ./Filechange/Filechange.hpp:1: ./Filechange/Filechange.cpp:14:24: error: expected expression
std::thread first ([&wtime,&f,&fn]() mutable {
^ Main.cpp:16:33: error: expected expression
OnFilechange("FileEvent", 0.5, [](char* txt){
^ 2 errors generated.
These are the files:
Main.cpp:
#include <lua.hpp>
#include <iostream>
#include <chrono>
#include <thread>
#include <stdio.h>
#include "Filechange/Filechange.hpp"
void wait(int seconds)
{
std::this_thread::sleep_for(std::chrono::seconds(seconds));
}
int main(int argc, char const *argv[])
{
lua_State *State = luaL_newstate();
OnFilechange("FileEvent", 0.5, [](char* txt){
std::cout << txt << std::endl;
});
lua_close(State);
return 0;
}
Filechange.cpp:
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <fstream>
char* StringToChar(std::string str){
char* Array = new char[str.length() + 1];
strcpy(Array,str.c_str());
return Array;
}
void OnFilechange(const char *f, float wtime, void (*fn)(char* txt)){
std::thread first ([&wtime,&f,&fn]() mutable {
std::ifstream file(f);
std::string str;
std::string filecontents;
while (std::getline(file,str)){
filecontents += str;
filecontents.push_back('\n');
}
char* LastContents = StringToChar(filecontents);
char* CurrentContents = StringToChar(filecontents);
while (true){
if (wtime != 0){
std::this_thread::sleep_for(std::chrono::milliseconds(int(wtime*1000)));
}
filecontents = "";
while (std::getline(file,str)){
filecontents += str;
filecontents.push_back('\n');
}
CurrentContents = StringToChar(filecontents);
if (strcmp(LastContents, CurrentContents) != 0){
LastContents = StringToChar(filecontents);
fn(StringToChar(filecontents));
}
}
});
}
Filechange.hpp:
#include "Filechange.cpp"
#ifndef FILECHANGE_HPP
#define FILECHANGE_HPP
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <fstream>
void OnFilechange(const char *f,float wtime,void (*fn)(char txt));
#endif
There's also a extension less file named FileEvent which will change in the runtime using other code files.
The Filechange.cpp and Filechange.hpp are in a folder named "Filechange"
This function:
void OnFilechange(const char *f, float wtime, void (*fn)(char* txt))
expects a function pointer, and a lambda in g++ is not implemented as a function pointer. Instead, you should declare the function to take a std::function, as in:
void OnFilechange(const char *f, float wtime, std::function<void(char *)> fn)
You may also need #include <functional> to get the declaration of std::function.
use -std=c++17 in g++ if possible as g++ defaulted to c++98
I've some C++ APIs like below:
API1(std::string str, std::vector<std::string> vecofstr);
I want to call this API from a C code. How can i provide a C wrapper for this ?
std::string str
=>
I can probably use char* for std::string
&
std::vector<std::string> vecofstr =>
array of char* for vector of string like
char* arrOfstrings[SIZE];
This is what the corresponding C header (and its C++ implementation) could look like:
Declaration
#ifdef __cplusplus
extern "C"
#endif
void cAPI1(const char *str, const char * const *vecofstr, size_t vecofstrSize);
Implementation
extern "C" void cAPI1(const char *str, const char * const *vecofstr, size_t vecofstrSize)
{
API1(str, {vecofstr, vecofstr + vecofstrSize});
}
[Live example]
The above assumes that the C code will use zero-terminated strings for all string arguments. If that is not the case, the parameters of cAPI1 must be modified accordingly (ideally based on what representation of strings is actually used by the C code).
1.api.h
#ifndef API_H_
#define API_H_
#include <vector>
#include <string>
void api1(std::string& str, std::vector<std::string>& vecofstr);
#endif
.2. api.cpp
#include "api.h"
#include <iostream>
void api1(std::string& str, std::vector<std::string>& vecofstr) {
std::cout << str << std::endl;
for (size_t i=0; i<vecofstr.size(); i++) {
std::cout << vecofstr[i] << std::endl;
}
}
3.wrapper.h
#ifndef WRAPPER_H_
#define WRAPPER_H_
#define SIZE 2
#ifdef __cplusplus
extern "C" {
#endif
extern void wrapper1(char* p, char* [SIZE]);
#ifdef __cplusplus
};
#endif
#endif
4.wrapper.cpp
#include <string>
#include "wrapper.h"
#include "api.h"
#ifdef __cplusplus
extern "C" {
#endif
void wrapper1(char* p, char* ps[SIZE]) {
std::string str(p);
std::vector<std::string> vecofstr;
for (size_t idx=0; idx<SIZE; idx++) {
vecofstr.push_back(ps[idx]);
}
api1(str, vecofstr);
}
#ifdef __cplusplus
};
#endif
.5. test.c
#include "wrapper.h"
int main(void)
{
char* p = "hello world";
char* ps[] = {"world", "hello"};
wrapper1(p, ps);
return 0;
}
.6. compile
gcc -c api.cpp wrapper.cpp
gcc test.c -o test wrapper.o api.o -lstdc++
.7. run
./test
hello world
world
hello
I am trying to create a input handler using multi threading with the SDL2 Library; however, when I try to put a thread in a class it won't compile and gives me this error...
error: cannot convert 'inputHandlerClass::getInput' from type 'int (inputHandlerClass::)(void*)' to type 'SDL_ThreadFunction {aka int (*)(void*)}'
I'm pretty sure that its the way I am passing the function name (fn) to the SDL_CreateThread function.
This is the source.cpp file
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <SDL_thread.h>
#include <SDL_mixer.h>
#include "..\include\gameClass.hpp"
#include "..\include\inputHandlerClass.hpp"
int main(int argc, char *argv[]){
inputHandlerClass inputHandler;
inputHandler.startThread();
std::cout << "hello world";
return 0;
}
This is the inputHandlerClass.hpp
#include <SDL_thread.h>
#include <iostream>
class inputHandlerClass{
private:
SDL_Thread *thread;
int threadReturnValue;
public:
inputHandlerClass();
int getInput(void *ptr);
void startThread();
};
//Default Constructor
inputHandlerClass::inputHandlerClass(){
this->thread = SDL_CreateThread(getInput, "inputThread", this);
}
int inputHandlerClass::getInput(void *ptr){
int cnt;
for(cnt= 0; cnt < 10; ++cnt){
std::cout << "counter: " << cnt << std::endl;
SDL_Delay(50);
}
return cnt;
}
void inputHandlerClass::startThread(){
SDL_WaitThread(this->thread, &this->threadReturnValue);
}
SDL_CreateThread expects a pointer to a regular function with int(void *ptr) signature as first parameter, however you are providing a non-static member function (not even a pointer because member functions aren't getting implicitly converted to a pointer). You should redeclare getInput as static. this pointer will be available as ptr.
I am a C++ noob, fiddling with the following problem for some hours now. Hopefully, someone can enlighten me.
I had a cpp file with content like so:
test.cpp file content
#include <iostream>
#include <exception>
#include <stdlib.h>
#include <string.h>
using std::cin; using std::endl;
using std::string;
string foobar(string bar) {
return "foo" + bar;
}
int main(int argc, char* argv[])
{
string bar = "bar";
System::convCout << "Foobar: " << foobar(bar) << endl;
}
This one compiles and runs well. Now I'd like to put foobar into an external library:
mylib.h file content
string foobar(string bar);
mylib.cpp file content
#include <string.h>
using std::cin; using std::endl;
using std::string;
string foobar(string bar) {
return "foo" + bar;
}
test.cpp file content
#include <iostream>
#include <exception>
#include <stdlib.h>
#include "mylib.h"
int main(int argc, char* argv[])
{
string bar = "bar";
System::convCout << "Foobar: " << foobar(bar) << endl;
}
I adjusted my Makefile, so that test.cpp compiles and links mylib, but I always encounter the error:
test.cpp::8 undefined reference to `foobar(std::string)
How do I have to handle string arguments? My attempts seems to be completely wrong here.
Regards
Felix
The C++ standard library type std::string is in the header string. To use it, you must include <string>, not <string.h>. Your mylib.h should look something like
#ifndef MYLIB_H
#define MYLIB_H
#include <string>
std::string foobar(std::string bar);
#endif
and your mylib.cpp should include it:
#include "mylib.h"
std::string foobar(std::string bar) {
return "foo" + bar;
}
Note that it may be unnecessary to pass bar by value. Looking at your code, a const reference might do.
I'm getting two errors in main that have me stumped:
"no matching function for call"
"invalid initialization of non-const reference of type 'int&' from a temporary of type 'int*'"
Could anyone lend a hand? thanks!
header
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cctype>
#include <cstdlib>
using namespace std;
void extern input(ifstream&, ofstream&, int&, int&);
#endif // HEADER_H_INCLUDED
main
#include "header.h"
using namespace std;
int main()
{
int grade;
int list[8];
ifstream inData;
ofstream outData;
inData.open("Ch9_Ex4Data.txt");
if (!inData)
{
cout << "Cannot open the input file."
<< endl;
return 1;
}
outData.open("DataOut.txt");
inData.get(grade); // << ERROR 1 HERE
while (inData)
{
input(inData, outData, grade, list); // << ERROR 2 HERE
}
output (outData, list)
return 0;
}
Error 1 is because inData.get() does not take an int, you should do
grade = inData.get();
and the second is because list is actually an int* and not an int so the fourth parameter in input() should be an int* and not an int&
An int[] is not an int&. An int& is a reference to an integer. int list[8] is an array of 8 integers. They are not the same thing.
For your first error, you're passing an int instead of a char or char*. See below for get prototypes:
istream::get
public member function
int get();
istream& get ( char& c );
istream& get ( char* s, streamsize n );
istream& get ( char* s, streamsize n, char delim );
istream& get ( streambuf& sb);
istream& get ( streambuf& sb, char delim );
For the second error, you're wrongly passing an array of int where the function is expecting a int&.