I have been having some trouble using RapidXML to parse a string. I receive an error from within Eclipse claiming the parse function does not exist.
make all
Building file: ../search.cpp
Invoking: Cross G++ Compiler
g++ -DDEBUG -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"search.d" -MT"search.d" -o "search.o" "../search.cpp"
../search.cpp: In function ‘void search(CURL*, CURLcode, std::string, std::string)’:
../search.cpp:29:27: error: no matching function for call to ‘rapidxml::xml_document<>::parse(const char*)’
../search.cpp:29:27: note: candidate is:
../rapidxml-1.13/rapidxml.hpp:1381:14: note: template<int Flags> void rapidxml::xml_document::parse(Ch*) [with int Flags = Flags, Ch = char]
make: *** [search.o] Error 1
The following code raises an error:
rapidxml::xml_document<> doc; // This has no errors
doc.parse<0>(data.c_str()); // This line raises the error (data is a string)
For reference here is the online documentation:
http://rapidxml.sourceforge.net/manual.html#namespacerapidxml_1parsing
RapidXML comes as four header files:
rapidxml_iterators.hpp
rapidxml_print.hpp <--contains errors, but build is successful with them
rapidxml_utils.hpp <--contains errors, but build is successful with them
rapidxml.hpp <--linked by program, contains parse function
How do I resolve the error in my code, and do I first need so resolve compiler errors in the headers somehow?
The problem is that the char* returned from calling c_str() on a std::string is actually a const char* which is no good for the parse function (parsing actually changes the string that it parses in rapidXML). This means we need to copy the string before we parse it
xml_document<> doc;
string str; // String you want to parse
char* cstr = new char[str.size() + 1]; // Create char buffer to store string copy
strcpy (cstr, str.c_str()); // Copy string into char buffer
doc.parse<0>(cstr); // Pass the non-const char* to parse()
// Do stuff with parsing
delete [] cstr; // free buffer memory when all is finished
I have not attempted to compile the above so there maybe errors, the point is that c_str() returns a const char* and parse() must take a non-const char*. Hope this helps. As for your headers, I usually get away with only using
rapidxml.hpp
rapidxml_print.hpp
included in my source files. You have no linker issues because RapidXML is header only implementation (which makes it nice in my opinion).
As #Hydranix pointed out in the comments,
doc.parse<0>(&str[0]);
works perfectly well. I parsed some big xml files using it.
Related
I'm having difficulty figuring out exactly how to use execvp in C++. I'm not having any issues getting my code to work, but I'm specifically trying to figure out how to do it in a way that doesn't make the compiler complain.
I have looked at various questions on Stack Overflow and other resources, but I have been unable to find a solution that results in zero warnings from the compiler.
Consider the following C++ program, which prints its own source code:
#include <unistd.h>
int main(int argc, char *argv[])
{
char *args[3];
args[0] = "/bin/cat";
args[1] = __FILE__;
args[2] = NULL;
execvp(args[0], args);
return 0;
}
(I know that the return 0 should never be reached; I'm not so concerned with error handling in this question.)
When I compile it, the compiler emits two warnings:
$ g++ -Wall exec.cpp
exec.cpp: In function ‘int main(int, char**)’:
exec.cpp:6:15: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
args[0] = "/bin/cat";
^~~~~~~~~~
exec.cpp:7:15: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
args[1] = __FILE__;
^~~~~~~~
The compiled program successfully prints the source file. However, I'd really like to get the program to compile without any warnings. Since the compiler doesn't like that the string literals are being assigned to a pointer of type char* (not const char*), I suppose it would make sense to mark args as an array of const char* pointers. Consider this version of the program:
#include <unistd.h>
int main(int argc, char *argv[])
{
const char *args[3];
args[0] = "/bin/cat";
args[1] = __FILE__;
args[2] = NULL;
execvp(args[0], args);
return 0;
}
I would think that this program should compile and run with no warnings or errors, but the compiler does emit an error:
$ g++ -Wall exec.cpp
exec.cpp: In function ‘int main(int, char**)’:
exec.cpp:10:25: error: invalid conversion from ‘const char**’ to ‘char* const*’ [-fpermissive]
execvp(args[0], args);
^
In file included from exec.cpp:1:0:
/usr/include/unistd.h:581:12: note: initializing argument 2 of ‘int execvp(const char*, char* const*)’
extern int execvp (const char *__file, char *const __argv[])
^~~~~~
I also tried declaring args as char const *args[3], but the compiler emits the same error. The only way I am able to get it to compile with no warnings is by casting args in the call to execvp:
const char *args[3];
...
execvp(args[0], (char* const*)args);
This version compiles without warnings and runs successfully. However, I prefer to avoid casting when I can, because it makes it harder for me to reason about the type conversions going on.
Are one of the two working ways that I have shown above the best way to create an argument array to pass to execvp, or is there a better way that is clear and does not result in the compiler complaining?
I am using two different compilers - g++ 6.2.0 for native compilation on Ubuntu x86_64, and g++ 4.5.3 for cross compilation to an ARM platform.
Edit:
I do not believe that my question is a duplicate of this question. I understand the different effects of using const in different ways with respect to a char* variable. I am specifically asking which type is conventionally used for execvp calls, which is not answered by the linked question.
It is very common for any medium-to-large project to replace printf with a custom log function. Here is a minimal C++ example and its usage:
#include <stdio.h>
#include <stdarg.h>
#include <string>
void log_printf(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap); // real code obviously does something fancier
va_end(ap);
}
int main() {
std::string x = "Hello";
// correct code
printf("String is %s\n", x.c_str());
log_printf("String is %s\n", x.c_str());
// incorrect code
printf("String is %s\n", x); // bad line 1
log_printf("String is %s\n", x); // bad line 2
}
The simple logger receives a variable amount of arguments and calls vprintf to output them to standard output. The lines under 'correct code' demonstrate correct usage of this logger. My question involves the 'bad' lines, where a string object is incorrectly passed instead of a pointer to the character buffer.
Under GCC 4.6 (tested under Linux) neither of the bad lines can compile, which is a good thing because I want to catch such incorrect usage. The error is:
error: cannot pass objects of non-trivially-copyable type ‘std::string {aka struct std::basic_string<char>}’ through ‘...’
However in GCC 5.1 it has apparently become possible to pass non-trivially-copyable objects, and the compilation succeeds. If I use -Wall then only 'bad line 1' raises a warning about an unexpected argument type, but 'bad line 2' with the log_printf compiles without issue in any case. Needless to say both lines produce garbage output.
I can catch 'bad line 1' with -Wall -Werror, but what about 'bad line 2'? How can I cause it to also generate a compilation error?
For your own functions you need to use a common function attribute call format:
void log_printf(const char* fmt, ...) __attribute__((format (printf, 1, 2)));
void log_printf(const char* fmt, ...) {
...
}
Note that the attribute must be set on a function declaration, not the definition.
The first argument to the format attribute is the style, in this case printf (scanf is also possible, for functions that works like scanf), the second argument is the format string, and the third argument is where the ellipsis ... is. It will help GCC check the format strings like for the standard printf function.
This is a GCC extension, though some other compilers have adopted it to become GCC compatible, most notably the Intel C compiler ICC and Clang (the standard compiler used on OSX and some BSD variants). The Visual Studio compiler does not have this extension, and I know of no similar thing for Visual C++.
I'm trying to wrap a c++ function called i_receive() by following this tutorial, I first created a wrap.c file, the content of this file is like this:
int i_receive(const uint32_t *f, int32_t t){
static int (*real_i_receive)(const uint32_t *, int32_t)=NULL;
printf("hello world");
return real_i_receive;
}
I compiled this file with gcc -fPIC -shared -o wrap.so wrap.c -ldl, when I used the LD_PRELOAD to run some C++ code with LD_PRELOAD=/full/path/to/wrap.so ./mycppcode I got this message:
ERROR: ld.so: object '/full/path/to/wrap.so' from LD_PRELOAD cannot be preloaded: ignored`.
I was guessing the reason might be that the wrap file is a C file, and I'm using it with C++ code, am I right?
I changed the file to wrap.cc with the same content, when compiling in the same way as before, I got:
ERROR: invalid conversion from 'int (*)(const uint32_t*, int32_t)' to 'int'
First of all, your 2nd error your are getting becase you are returning a Pointer to function type instead of a int type.
If you want to return an int, call the function from the code :
return real_i_receive(f,t);
Notice the "()" which means a function call.
Regarding your guess : it doesn't matter if you are using C or C++ code, the libaries are all assembly code.
One difference between exporting C functions and C++ functions is the name mangling. You would rather export a function as a C function to be able to access it inside your library through unmagled name.
To export a function without name mangling it, you can use extern "C" .
Replace
return real_i_receive;
with
return real_i_receive(f, t);
As it is, the return type of your function is int but you're returning a function pointer.
I'm compiling and linking a cpp file against a pre-compiled library, and I'm getting an "undefined reference" error.
Firstly, this is the command (the library in question is quicknet3, the program I'm compiling is trapper):
g++ -w -g -I. -g -O3 -pipe -Wall -I/home/install/x86_64/include/quicknet3 -L/home/install/x86_64/lib -lquicknet3 -lintvec -lfltvec -o trapper trapper.cpp CMyException.cpp
Here's the undefined reference error:
/tmp/ccFuVczF.o: In function 'main':
trapper.cpp:1731: undefined reference to 'QN_InFtrLabStream_PFile::QN_InFtrLabStream_PFile(int, char const*, _IO_FILE*, int)'
The call in trapper.cpp (line 1731) is:
IN_PFILE = new QN_InFtrLabStream_PFile(0, "", fp, 1);
where fp is a FILE *, assigned as the result of an fopen call beforehand.
The constructor being called is defined in the relevant header file (QN_Pfile.h), as follows:
class QN_InFtrLabStream_PFile : public
QN_InFtrLabStream
{
public:
QN_InFtrLabStream_PFile(int a_debug, const char* a_dbgname, FILE* a_file, int a_indexed);
(... other declarations ...)
}
The definition of the constructor is indeed given in QN_Pfile.cc:
QN_InFtrLabStream_PFile::QN_InFtrLabStream_PFile(int a_debug,const char* a_dbgname, FILE* a_file, int a_indexed) : log(a_debug, "QN_InFtrLabStream_PFile", a_dbgname),file(a_file),indexed(a_indexed),buffer(NULL),sentind(NULL)
{
(... the usual constructor stuff :P ...)
}
I compiled the quicknet3 library myself, without error, and installed it to /home/install/x86_64/lib/libquicknet3.a
So, I can't understand why the call from trapper.cpp is unable to find the reference to this constructor definition. The g++ arguments of -L/home/install/x86_64/lib -lquicknet3 should do the trick, right?
Any ideas?
Thanks,
Roy
I notice that you're mixing FILE* and _IO_FILE*. I'm not familiar with the latter, are you sure they're one and the same?
A quick workaround is to add /home/install/x86_64/lib/libquicknet3.a to g++ commandline.
I you want to investigate further, if g++ is picking another copy of libquicknet3, you can pass -v to g++ so it will output its searching paths.
FILE is a typedef of _IO_FILE. Your linker is treating it as a unique type.
You could try:
IN_PFILE = new QN_InFtrLabStream_PFile(0, "", (FILE *)fp, 1);
to see if this resolve your constructor.
(FILE is defined in stdio.h, _IO_FILE in libio.h if you're interested)
Refactoring legacy code, I came across this function (pseudocode):
int getMessage( char * buffer, int size = 300 );
Gee, look at that buffer just waiting to overflow. So I came up with a function using std::string, and thought it would be nice to use function overloading:
int getMessage( std::string & buffer );
So far, so good. But when I try to call the function with a string:
std::string buffer;
int rc = getMessage( buffer );
I get this error:
cannot convert 'std::string' to 'char*' for argument '1' to 'int getMessage(char*, int)'
Obviously, the compiler (GCC 4.1.2) tries hard to convert std::string to char* to satisfy the first function's parameter list (using the default value to satisfy the second parameter), gives up, but doesn't try the second function...
I wouldn't have a problem working around this issue, but I'd like to know why this fails, and whether there would be a way to make it work as intended.
It works as expected on my GCC 4.3.2, maybe you misspelled the name of the overload? There's no conversion from std::string to char*, so the compiler shouldn't have any problems choosing the correct overload.
$ cat test.cpp
#include <string>
#include <stdio.h>
int getMessage( char * buffer, int size = 300 )
{
printf("1\n");
return 1;
}
int getMessage( std::string & buffer )
{
printf("2\n");
return 2;
}
int main()
{
std::string buffer;
buffer = "Hello";
int rc = getMessage( buffer );
}
$ g++ test.cpp -Wall -pedantic
test.cpp: In function ‘int main()’:
test.cpp:20: warning: unused variable ‘rc’
$ ./a.out
2
$ $ g++ -v 2>&1|tail -n1
gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)
$
Hmmm. There is no implicit conversion from std::string to char*, so that can't be your problem. Are you sure your new function is visible at the call site?
You said this is pseudo-code. Are you leaving something out? Are these template functions or member functions? Please post more of the code or try to boil it down to a smaller test case.
My guess is that the overload for the string version of the function isn't visible where you called it. Are you sure that it is in the correct header file, and is spelled correctly?
Do you have a declaration of `int getMessage( std::string & buffer );' in scope? You are hitting this error because the proper function is not being found.
As always, once the problem is solved, the solution is painfully trivial and should have been obvious all along.
So I came up with a function using std::string...
...in my working directory, which compiled just fine, but -I and -L in my makefile were still pointing at the previous version of the library, which was blissfully unaware of the new function.
Sorry for the bother. I've been an idiot. I hope this doesn't become a habit. ;-)