I try to avoid mixed QString and char* types in a QT program. I have a conversation function that returns a pointer of the data inside the QString, but I get very strange results. Whats wrong with this code?
Compiler and environment gcc (Debian 4.9.2-10) 4.9.2
Flags via qmake: QMAKE_CXXFLAGS += -std=c++11
Code snippet:
#include <QCoreApplication>
#include <iostream>
#define PCH(m) ( m.toAscii().data() )
// get the pointer short scripted
const char* CH(QString msg) {
const char* res = msg.toAscii().data();
return res;
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
const QString qformat = "%s does not work!";
const QString qvalue = "embedding";
// Works not
qDebug(CH(qformat), CH(qvalue));
// Works
qDebug(qformat.toAscii().data(), qvalue.toAscii().data());
// Works too but macro
qDebug(PCH(qformat), PCH(qvalue));
return app.exec();
}
Results
%s does not work! does not work!
embedding does not work!
embedding does not work!
Here you are copying QString to function, and return pointer to already destroyed data inside function. This is known undefined behavior, since you are returning pointer to garbage. Return QString.
const char* CH(QString msg) {
const char* res = msg.toAscii().data();
return res;
}
You should be using qDebug() and the formatting mechanism built into QString itself. You should also use QStringLiteral instead of depending on default string conversions - after all you've stated that you care about such things:
#include <QtCore>
int main()
{
const auto qformat = QStringLiteral("%1 does work!");
const auto qvalue = QStringLiteral("embedding");
qDebug() << qformat.arg(qvalue);
qDebug() << qformat.arg(0x7A01173C2, 0, 16);
}
The QStringLiteral, used on modern compilers, does not create an 8-bit C-string. It assembles a binary internal representation of a QString at compile time, and stores it in a read-only memory section of your executable. This is the only way to avoid runtime costs of string encoding.
There is no benefit whatsoever in doing a roundtrip via QString if you already have UTF8 encoded string literals or C-style strings that are UTF8 encoded. If you need to use C-style strings/string literals, use them directly with qDebug:
#include <QtCore>
int main() {
const char format[] = "%s does not work!";
const char value[] = "embedding";
qDebug(format, value);
}
If you need to pass temporary C-style strings, use QByteArray, but that's really a lot of code with very little to show for it - it's so verbose as to have a very bad code smell. So don't do it like this:
#include <QtCore>
QByteArray CH(const QString &msg) {
return msg.toLocal8Bit();
}
int main()
{
auto qformat = QStringLiteral("%s does work!");
auto qvalue = QStringLiteral("embedding");
qDebug(CH(qformat).constData(), CH(qvalue).constData());
}
Related
Say I want to write a vector-based string (String) just for the heck of it and I want an efficient c_str() operation on it.
Seems easy enough if I simply ensure the following:
//Make sure end() points to a '\0' and that '\0' is in allocated space
void afterEachNonConst() { reserve(size()+1); *(end()) = '\0'; }
Then c_str() is "just" begin() converted to const char*:
//Return C-string
const char* c_str() const { return (const char*)(&((*this)[0])); }
(I don't know how to do it shorter; the type system seems very unwilling to convert vector<char>::const_iterator to const char* even though they should be the same).
With that I want to override every non-const non-void method (except for and reserve) with:
auto ret = vector::method(arg1, arg2, arg3, ...);
//^can't it be just something like `auto ret = super();` ??
afterEachNonConst();
return ret;
and every non-const void method with:
vector::method(arg1, arg2, arg3, ...);
afterEachNonConst();
I guess there's no reasonably elegant way to just let C++ metaprogramming do all the work (?). Can I at least get a listing of all vector method signatures into my text editor somehow?
Here's a compilable example I played with:
#include <iostream>
#include <vector>
#include <cstring>
#include <cassert>
class String : public std::vector<char> {
public:
//Initialize from c-string
String& operator=(const char* cstr) {
size_t length = strlen(cstr);
reserve(strlen(cstr) + 1);
resize(length);
for(iterator ptr = begin(); *ptr++=*cstr++; ); //this will copy the '\0' too, but only at end()
return *this;
}
String(const char* cstr){ (*this) = cstr; }
//Return C-string
const char* c_str() const { return (const char*)(&((*this)[0])); }
void push_back(char value){
vector::push_back(value);
afterEachNonConst();
};
private:
//Make sure end() points to a '\0' and that '\0' is in allocated space
void afterEachNonConst() { reserve(size()+1); *(end()) = '\0'; }
};
int main(int argc, char **argv)
{
using namespace std;
String a = "foobar";
assert(a.size() == strlen(a.c_str()));
a.push_back('_');
a.push_back('1');
assert(a.size() == strlen(a.c_str()));
cout<<a.c_str()<<endl;
return 0;
}
What you want to do cannot be done with metaprogramming. You'd need reflection as part of the language, which is IMHO sadly a missing feature of C++.
To get a list of the member functions of std::vector I'd go and open the standard, N4431 ยง23.3.6 and try to extract them from there.
If this is too "much work" you could also try to implement something using libclang or libTooling, though this seems by far easier as it really is. (I just had to do something similar)
Since the syntax of C++ is so extremely complicated, especially in combination with templates, parsing it is really hard. Sadly using the above libraries it's also very hard to reproduce a parsed member function declaration.
I was trying to convert a QString to char* type by the following methods, but they don't seem to work.
//QLineEdit *line=new QLineEdit();{just to describe what is line here}
QString temp=line->text();
char *str=(char *)malloc(10);
QByteArray ba=temp.toLatin1();
strcpy(str,ba.data());
Can you elaborate the possible flaw with this method, or give an alternative method?
Well, the Qt FAQ says:
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QString str1 = "Test";
QByteArray ba = str1.toLocal8Bit();
const char *c_str2 = ba.data();
printf("str2: %s", c_str2);
return app.exec();
}
So perhaps you're having other problems. How exactly doesn't this work?
Maybe
my_qstring.toStdString().c_str();
or safer, as Federico points out:
std::string str = my_qstring.toStdString();
const char* p = str.c_str();
It's far from optimal, but will do the work.
The easiest way to convert a QString to char* is qPrintable(const QString& str),
which is a macro expanding to str.toLocal8Bit().constData().
David's answer works fine if you're only using it for outputting to a file or displaying on the screen, but if a function or library requires a char* for parsing, then this method works best:
// copy QString to char*
QString filename = "C:\dev\file.xml";
char* cstr;
string fname = filename.toStdString();
cstr = new char [fname.size()+1];
strcpy( cstr, fname.c_str() );
// function that requires a char* parameter
parseXML(cstr);
EDITED
this way also works
QString str ("Something");
char* ch = str.toStdString().C_str();
Your string may contain non Latin1 characters, which leads to undefined data. It depends of what you mean by "it deosn't seem to work".
If your string contains non-ASCII characters - it's better to do it this way:
s.toUtf8().data() (or s->toUtf8().data())
the Correct Solution Would be like this
QString k;
k = "CRAZYYYQT";
char ab[16];
sprintf(ab,"%s",(const char *)((QByteArray)(k.toLatin1()).data()) );
sprintf(ab,"%s",(const char *)((QByteArray)(k.toStdString()).data()));
sprintf(ab,"%s",(const char *)k.toStdString().c_str() );
qDebug()<<"--->"<<ab<<"<---";
Qt provides the simplest API
const char *qPrintable(const QString &str)
const char *qUtf8Printable(const QString &str)
If you want non-const data pointer use
str.toLocal8Bit().data()
str.toUtf8().data()
It is a viable way to use std::vector as an intermediate container:
QString dataSrc("FooBar");
QString databa = dataSrc.toUtf8();
std::vector<char> data(databa.begin(), databa.end());
char* pDataChar = data.data();
The program fails while compiling the code. Compiler points to printf("Version = '%s'\n", gABXVER). I guess that I actually can't write gABXVER = "V1R1", but I don't have any other idea.
class CISPFVar_BINSTR : public CISPFVar
{
protected:
char* m_pBuffer;
long m_bDefined;
public:
...
void Initialize(char* szName, long lSize, int bDefineVar = 1)
{
Uninitialize();
ZStrToCharArray(szName, m_cName, 8);
m_Size = lSize+1;
m_pBuffer = (char*)malloc(m_Size);
m_pBuffer[0] = 0;
if (bDefineVar)
ISPLINK(__VDEFINE, m_cName, m_pBuffer, __BINSTR, &m_Size);
m_bDefined = bDefineVar;
}
...
};
CISPFVar_BINSTR gABXVER;
char szLoadLibraryPath[50];
int main(
int argc,
char* argv[])
{
if (argc > 1)
if (argv[1]) strcpy(szLoadLibraryPath, argv[1]);
gABXVER.Initialize("ABXVER",4);
gABXVER = "V1R1";
printf("Version = '%s'\n", gABXVER);
return 0;
};
When you use %s in printf family of functions, the corresponding argument type needs to be const char* or something that can be converted to const char*. The argument you are using is not such a type. Perhaps you meant to use:
printf("Version = '%s'\n", gABXVER.m_pBuffer);
The compiler should compile just fine (with possible warnings for printf) because printf doesn't care what you pass to it (beyond the first parameter) or whether it matches the format string. Modern compilers or error checking progs like lint will issue a warning if the params obviously don't match, and if you have a setting "treat warnings as errors", the prog may fail to compile.
That said, CISPFVar_BINSTR needs a public copy constructor if you want to pass it as a parameter by value to a function (because at least semantically a copy will be made). Does it have one? As others remarked it's customary to help your helpers by providing any information you have. Here we are badly missing the compiler errors. (You can edit your post at any time.)
I could imagine that the class has a conversion to char* or std::string, so it may suffice to try either printf("Version = '%s'\n", (char *)gABXVER) or printf("Version = '%s'\n", (std::string(gABXVER)).c_str() ).
You can only printf things that have format specifiers designed specifically for them. There is no format specifier that accepts a value of class type, so you cannot printf one directly.
The best thing you can do is explicitly convert your object to a const char* and pass the result to printf.
In c++ you can use many techniques to implement things like streaming operators
#include <iostream>
class Whatever
{
int value = 42;
public:
int Get() const {
return value;
}
friend std::ostream& operator<<(std::ostream&, Whatever const&);
};
std::ostream& operator<<(std::ostream& os, Whatever const& what) {
os << what.Get();
return os;
}
int main() {
Whatever x;
std::cout << x << std::endl;
}
printf is unsafe
In effect, you're doing serialization of your object into a readable string.
I was trying to convert a QString to char* type by the following methods, but they don't seem to work.
//QLineEdit *line=new QLineEdit();{just to describe what is line here}
QString temp=line->text();
char *str=(char *)malloc(10);
QByteArray ba=temp.toLatin1();
strcpy(str,ba.data());
Can you elaborate the possible flaw with this method, or give an alternative method?
Well, the Qt FAQ says:
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QString str1 = "Test";
QByteArray ba = str1.toLocal8Bit();
const char *c_str2 = ba.data();
printf("str2: %s", c_str2);
return app.exec();
}
So perhaps you're having other problems. How exactly doesn't this work?
Maybe
my_qstring.toStdString().c_str();
or safer, as Federico points out:
std::string str = my_qstring.toStdString();
const char* p = str.c_str();
It's far from optimal, but will do the work.
The easiest way to convert a QString to char* is qPrintable(const QString& str),
which is a macro expanding to str.toLocal8Bit().constData().
David's answer works fine if you're only using it for outputting to a file or displaying on the screen, but if a function or library requires a char* for parsing, then this method works best:
// copy QString to char*
QString filename = "C:\dev\file.xml";
char* cstr;
string fname = filename.toStdString();
cstr = new char [fname.size()+1];
strcpy( cstr, fname.c_str() );
// function that requires a char* parameter
parseXML(cstr);
EDITED
this way also works
QString str ("Something");
char* ch = str.toStdString().C_str();
Your string may contain non Latin1 characters, which leads to undefined data. It depends of what you mean by "it deosn't seem to work".
If your string contains non-ASCII characters - it's better to do it this way:
s.toUtf8().data() (or s->toUtf8().data())
the Correct Solution Would be like this
QString k;
k = "CRAZYYYQT";
char ab[16];
sprintf(ab,"%s",(const char *)((QByteArray)(k.toLatin1()).data()) );
sprintf(ab,"%s",(const char *)((QByteArray)(k.toStdString()).data()));
sprintf(ab,"%s",(const char *)k.toStdString().c_str() );
qDebug()<<"--->"<<ab<<"<---";
Qt provides the simplest API
const char *qPrintable(const QString &str)
const char *qUtf8Printable(const QString &str)
If you want non-const data pointer use
str.toLocal8Bit().data()
str.toUtf8().data()
It is a viable way to use std::vector as an intermediate container:
QString dataSrc("FooBar");
QString databa = dataSrc.toUtf8();
std::vector<char> data(databa.begin(), databa.end());
char* pDataChar = data.data();
In C++ I wanted to define a constant that I can use in another function, A short answer on how to do this will be fine..
Lets say at the beginning of my code I want to define this constant:
//After #includes
bool OS = 1; //1 = linux
if (OS) {
const ??? = "clear";
} else {
const ??? = "cls";
}
I don't know what type to use to define the "clear" string... I'm so confused.
Later on I want to use it within a function:
int foo() {
system(::cls); //:: for global
return 0;
}
How would I define the string up top, and use the string down below? I heard char only had one character and things... I'm not sure how to use , since it says it's converting string into const char or something.
char* isn't quite a char. char* is basically a string (it's what strings were before C++ came along).
For illustration:
int array[N]; // An array of N ints.
char str[N]; // An array of N chars, which is also (loosely) called a string.
char[] degrades to char*, so you'll often see functions take a char*.
To convert std::string to const char*, you can simply call:
std::string s;
s.c_str()
In this case, it's common to use the preprocessor to define your OS. This way you can use the compiler to do the platform specific stuff:
#ifdef OS_LINUX
const char cls[] = "clear";
#elif OS_WIN
const char cls[] = "cls";
#endif
One thing you may want to consider is making it a function. This avoids nasty dependencies of global construction order.
string GetClearCommand() {
if (OS == "LINUX") {
return "clear";
} else if (OS == "WIN") {
return "cls";
}
FAIL("No OS specified?");
return "";
}
What it looks like you're trying to do is this:
#include <iostream>
using namespace std;
#ifdef LINUX
const char cls[] = "LINUX_CLEAR";
#elif WIN
const char cls[] = "WIN_CLEAR";
#else
const char cls[] = "OTHER_CLEAR";
#endif
void fake_system(const char* arg) {
std::cout << "fake_system: " << arg << std::endl;
}
int main(int argc, char** argv) {
fake_system(cls);
return 0;
}
// Then build the program passing your OS parameter.
$ g++ -DLINUX clear.cc -o clear
$ ./clear
fake_system: LINUX_CLEAR
Here's the problem, you're suffering from going out of scope with the variables. If I declare something within brackets, it only exists within the brackets.
if( foo ){
const char* blah = "blah";
}
Once we leave the if statement, the variable blah disappears. You'll need to instantiate it non-locally to whatever brackets you write. Hence:
void Bar(){
const char* blah = "blah";
if( foo ){
//blah exists within here
}
}
However, blah will not exist outside of Bar. Get it?
Yet another option is to create a class with a bunch of static methods. Create a new method for each command. Something like:
// in sys-commands.h
class SystemCommands {
public:
static char const* clear();
static char const* remove();
};
This gives you a few nice options for the implementation. The nicest one is to have a separate implementation file for each platform that you select during compile time.
// in sys-commands-win32.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "cls"; }
char const* SystemCommands::remove() { return "erase /f/q"; }
// in sys-commands-macosx.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "/usr/bin/clear"; }
char const* SystemCommands::remove() { return "/bin/rm -fr"; }
Which file gets compiled will determine which command set will be used. Your application code will look like:
#include <cstdlib>
#include "sys-commands.h"
int main() {
std::system(SystemCommands::clear());
return 0;
}
Edit: I forgot to mention that I prefer static functions to global constants for a bunch of reasons. If nothing else, you can make them non-constant without changing their types - in other words, if you ever have to select the command set based on runtime settings, the user code does not have to change or even be aware that such a change occurred.
You can use a common header file and link to different modules depending on the systen:
// systemconstants.hpp
#ifndef SYSTEM_CONSTANTS_HPP_INCLUDED
#define SYSTEM_CONSTANTS_HPP_INCLUDED
namespace constants {
extern const char cls[]; // declaration of cls with incomplete type
}
#endif
In case of Linux, just compile and link to this one:
// linux/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "clear";
}
In case of Windows, just compile and link to this one:
// windows/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "cls";
}
System-specific translation units could be placed in specific subdirectories (linux/, windows/, etc) of which one could be automatically selected during the build process. This extends to many other things, not just string constants.