I would like to call the following code in C++, which I cannot change:
void getAge(char *name)
{
// do something
}
When I call it with getAge("hello");, it has the following warning:
warning: deprecated conversion from string constant to 'char*'
but there is no warning in C code. What is the difference, and how do I change the call to avoid the warning in C++?
the function […] can not be changed
Then write a wrapper around the function and copy the string – or, if you feel lucky (= you know that the string won’t be modified inside the original function), explicitly cast away const-ness:
void getAge(char const* name) {
the_namespace::getAge(const_cast<char*>(name));
}
If you’re unsure whether the function modifies its parameters, use something like the following – however, if that’s the case then calling the function with a string literal (getAge("hello")) would have been invalid anyway.
void getAge(char const* name) {
std::string buffer(name);
the_namespace::getAge(&buffer[0]);
}
Here we copy the string into a modifiable buffer and pass an address to its first character to the original function.
The safest way is to copy the string, then call the C function:
void getAgeSafe(const char* name)
{
std::vector<char> tmp = name?
std::vector<char>(name, name+1+strlen(name))
:std::vector<char>();
getAge( tmp.data() );
}
and call getAgeSafe from your C++ code.
A less safe way that relies on the C code never modifying the char* name would be to const_cast, again in a "wrapping" function:
void getAgeUnsafe(const char* name)
{
getAge( const_cast<char*>(name) );
}
but this time the name is more scary, as is the operation. If you call getAge with a compile time constant string like "bob", if getAge modifies its input, undefined behavior results (this is true in both C and C++ -- C++ at least warns you about it).
You can try getAge((char*)"hello").
In c++ you can write it like this,
void getAge(string name)
{
// do something
}
and also include the header file #include<string> because you are using string now
Related
I'm getting an unexpected behavior when passing a const string to a function as a parameter.
I have this function:
std::string getStatusByTopic(const std::string topic){
if (topic.compare(TOPIC_WP_SM_CMD) == 0)
return state_to_string(STATUSES::WP_HANDLER_STATUS);
}
Which is not totally implemented yet.
And I have this function:
InsertStatus(getStatusByTopic(TOPIC_WP_SM_CMD),msg);
Which declared as:
void Msp::InsertStatus(const std::string status_topic, const std_msgs::String::ConstPtr& new_status)
I have 2 questions:
These functions have been compiled successfully, even though there's a possible usage where getStatusByTopic() returns nothing when its defined returned type is string. How is it possible?
When the code is executed, with the scenario that and getStatusByTopic(TOPIC_WP_SM_CMD) returns nothing. There's no runtime errors, more over - TOPIC_WP_SM_CMD is passed as parameter to InsertStatus() (which is defined ad "/some/topic/"). How is that possible?
Thanks.
I have some code that looks like this:
static std::string Foo(const std::string& blah)
{
if ( someWierdEdgeCase() ){
return false; // <-- this line has a compiler error
}
std::string resourcePath;
resourcePath.append("/assets/");
return resourcePath;
}
It used to compile fine, but then I upgraded to Xcode 5.1, and now it no longer compiles. The error I get is the following one:
No viable conversion from 'bool' to 'std::string'
I would like to know what I should replace 'return false' with so that this works the way it used to.
Normally, I would be happy to return something other than false, and clearly that is not good behavior. But somehow this code used to compile and run, and I want to understand what it was doing, in case some other part of this codebase is relying on what is certainly weird behavior.
This:
return false; // <-- this line has a compiler error
There is no standard way to convert bool to std::string (please correct me if there is or was something special in gcc (the old XCode mac compiler)). This means that your code base used to contain explicit code to convert the bool to string.
If it is not compiling now this suggests this conversion was removed from your code base.
A couple of people of suggested alternatives. But I doubt any of these are going to work. As the old code had a depedency on how it used to work. So making any specific recomendation will depend on working out how the old code compiled and what it returned when someWierdEdgeCase() is true. Basically you need to replicate this behavior.
Otherwise you need to hunt down all used cases in your code and change the behavior to match the new behavior. In this case I would change the name of the function. Re-Compile and see where the code breaks and check the behavior at each location and make sure it behaves the same.
static std::string Foo(const std::string& blah)
{
std::string resourcePath = "";
if ( someWierdEdgeCase() ){
return resourcePath; // <-- Now you're returning a string
}
resourcePath.append("/assets/");
return resourcePath;
}
If you need the return type to be - for whatever reason - not always present, return by pointer, instead of returning by value.
static yourType* Foo(const std::string& blah){
if ( someWierdEdgeCase() ){
return 0;
}
}
Then you can test and assign the function in the same line
yourType* result;
if(result = Foo("something")){
// the result was correct
Of course - since your function returns a std::string, you can return an empty string (""), or - also independent of the return type - throw an exception.
I had same issue that with the fact that my interface file and implementation file were using different data types in method declaration.Putting same data type on both place in method declaration error went away.
/* Thanks to anyone looking at this who might attempt to answer it. I'm really not trying to waste anyone's time here, but I have beat my head on this for about three days. I realize it is probably very simple for someone who understands it. I have tried most every possible combination I can think of and still get compiler errors.
C:\random\RNDNUMTEST.cpp(41) : error C2102: '&' requires l-value
I am trying to pass a pointer as a parameter to a function makeRndmNumber() for the member function fstream.open(). I want to open the file in RNDNUMTEST.cpp and then pass it to makeRndmNumber() so that it can be modified in some way. I have looked online for help, including this website, but I feel like I am overlooking something important or simple or maybe I am just missing the concept altogether.
This isn't for homework, I'm not a college student. Although I did go to school for it, it has been over 10 years since I've done any programming and I never really understood this that well to begin with. Any suggestions would be appreciated.
// These are only excerpts from the actual files.
// RndmNum_Class.h file
typedef void(fstream::*fStream_MPT)(const char*); // fStream_MPT (Member Pointer Type)
class RandomNumber {
public:
RandomNumber();
~RandomNumber() {};
static void loadDigits(double, double, char array[]);
static int getLastNDigits(char array[], int);
static int makeRndmNumber(int, int, fStream_MPT);
};
//*************************************************************8
//RndmNum_Class.cpp file
int RandomNumber::makeRndmNumber(int seed, int _fileSize, fStream_MPT FILE) {
......
}
//**************************************************************/
// RNDNUMTEST.cpp file
#include "RndmNum_Class.h"
int main() {
const char* RNDM_FILE = "c:\\RandomFile.txt";
fstream FStream_Obj;
// FStream_Obj.open(RNDM_FILE);
fStream_MPT FileMembPtr = &FStream_Obj.open(RNDM_FILE);
//fStream_MPT FileMembPtr = &fstream::open;
int seed = 297814;
int size = 20000;
cout << RandomNumber::makeRndmNumber(seed, size, FileMembPtr);
return 0;
}
This: &FStream_Obj.open(RNDM_FILE) is not taking the address of the function, it's trying to take the address of the return value of a call to that function. But that function returns void, hence the error message.
First, change the function definition from typedef void(fstream::*fStream_MPT)(const char*); to typedef void(fstream::*fstream_MPT)(const char*,ios_base::openmode), there is a default parameter you are forgetting.
Change the fStream_MPT FileMembPtr = &FStream_Obj.open(RNDM_FILE); to fStream_MPT FileMembPtr = &fstream::open; as per your comment, and add an additional parameter to makeRndNumber, a pointer to an fstream to operate on.
int RandomNumber::makeRndmNumber(int seed, int _fileSize, fStream_MPT FILE, fstream *file)
{
((*file).*FILE)("ExampleText",ios_base::in | ios_base::out);
}
FILE = fstream::open;
EDIT
This could also be done a little cleaner with std::function objects.
First redefine your type.
typedef std::function<void(const char*)> fStream_MPT;
Then when you assign, be sure to bind your objects.
fStream_MPT FILE = std::bind(&fstream::open,&file,std::placeholders::_1, ios_base::in | ios_base::out);
Then in your function you simply call the function
int RandomNumber::makeRndmNumber(int seed, int _fileSize, fStream_MPT FILE)
{
FILE("Example text");
}
It doesn't make any sense: member function pointers is used so you can apply different member functions somewhere without knowing which exact function is called. It is like passing the function's name around (except that the name is resolved at compile-time). It doesn't seem that this is what you want to do!
Even if you would correctly obtain the function's address (rather than trying to get the address of the result of calling open()), it wouldn't work because std::fstream::open() takes two arguments: the second argument is for the open-mode and it is defaulted to std::ios_base::in | std::ios_base::out.
I'm not quite sure what you really want to d but it seems you want to pass the file stream around. The normal way to do this is to pass a reference to a std::iostream as argument to the function. Well, actually you probably want to use a std::ifstream initially and hence pass the argument as std::istream&.
I have some C++ code written in C-style.
For some reasons I can't use C++ string and IO libraries, so for strings handling I should use only functions like sprintf, itoa, etc.
I want to replace C-style which requires temporary buffers
char buf[12];
itoa(x, buf, 16);
set_some_text(buf);
by the following code
class i2a
{
public:
explicit i2a(int value) { ::sprintf(buf, "%d", value); }
operator const char* () const { return buf; }
private:
char buf[12];
};
// usage:
set_some_text(i2a(x));
(Such classes can be written for char<->wchar_t convertions, etc.)
I see some cases when such classes will be dangerous:
For example, one can write
const char* someMeaningfulName = i2a(x);
// the right code should be i2a someMeaningfulName(x); or i2a someMeaningfulName = i2a(x);
set_some_text(someMeaningfulName);
In more complex case, a function which accepts text will not copy it, but will save pointer to it somewhere. For example it may be
class Foo { .... const char* p; };
Foo f(const char* text) { ... foo.p = text; return foo; }
it can be really unobvious, unlike const char* variable.
Is there a way to make such classes more secure?
Upd: why not std::string, boost::lexical_cast, boost::format, etc :
The code should work when compiled with -fno-except (C++ exceptions disabled - no throw, no stack unwinding). Also it should keep working on low memory conditions.
std::string, streams uses heap-allocated memory and at least throws bad_alloc.
When we have no free heap memory, usually we still have some kilobytes of stack (for example to write to user that we are out of memory and then make proper cleanup).
ATL and MFC String Conversion Macros are also written in this way. Calling the constructor directly like i2a(x) will create a temporary object that will live until the function to which it is passed is complete. So here: do_some(i2a(x)), the temporary object will be there until do_some() is complete.
Refer the Example section (example 2) of this msdn document
Here,
const char* someMeaningfulName = i2a(x);
set_some_text(someMeaningfulName);
This will not work as, the temporary object will be freed on the first statement itself. someMeaningfulName will be garbage. If you feel that as lack of security, all I can say is:
That's how Microsoft does it!
You will always get somewhere into troubles if you use const char* for your local variables.
You will have the same with const char* someMeaningfulName = std::string("foo").c_str();
If you can you should declare your local variable like this :
i2a someMeaningfulName(x);
set_some_text(someMeaningfulName);
You can also consider adding a copy constructor to i2a to avoid sharing the buffer between two instances.
I am working in C++ with two large pieces of code, one done in "C style" and one in "C++ style".
The C-type code has functions that return const char* and the C++ code has in numerous places things like
const char* somecstylefunction();
...
std::string imacppstring = somecstylefunction();
where it is constructing the string from a const char* returned by the C style code.
This worked until the C style code changed and started returning NULL pointers sometimes. This of course causes seg faults.
There is a lot of code around and so I would like to most parsimonious way fix to this problem. The expected behavior is that imacppstring would be the empty string in this case. Is there a nice, slick solution to this?
Update
The const char* returned by these functions are always pointers to static strings. They were used mostly to pass informative messages (destined for logging most likely) about any unexpected behavior in the function. It was decided that having these return NULL on "nothing to report" was nice, because then you could use the return value as a conditional, i.e.
if (somecstylefunction()) do_something;
whereas before the functions returned the static string "";
Whether this was a good idea, I'm not going to touch this code and it's not up to me anyway.
What I wanted to avoid was tracking down every string initialization to add a wrapper function.
Probably the best thing to do is to fix the C library functions to their pre-breaking change behavior. but maybe you don't have control over that library.
The second thing to consider is to change all the instances where you're depending on the C lib functions returning an empty string to use a wrapper function that'll 'fix up' the NULL pointers:
const char* nullToEmpty( char const* s)
{
return (s ? s : "");
}
So now
std::string imacppstring = somecstylefunction();
might look like:
std::string imacppstring( nullToEmpty( somecstylefunction());
If that's unacceptable (it might be a lot of busy work, but it should be a one-time mechanical change), you could implement a 'parallel' library that has the same names as the C lib you're currently using, with those functions simply calling the original C lib functions and fixing the NULL pointers as appropriate. You'd need to play some tricky games with headers, the linker, and/or C++ namespaces to get this to work, and this has a huge potential for causing confusion down the road, so I'd think hard before going down that road.
But something like the following might get you started:
// .h file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction();
}
// .cpp file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction() {
const char* p = ::somecstylefunction();
return (p ? p : "");
}
}
Now you just have to add that header to the .cpp files that are currently calling calling the C lib functions (and probably remove the header for the C lib) and add a
using namespace clib_fixer;
to the .cpp file using those functions.
That might not be too bad. Maybe.
Well, without changing every place where a C++ std::string is initialized directly from a C function call (to add the null-pointer check), the only solution would be to prohibit your C functions from returning null pointers.
In GCC compiler, you can use a compiler extension "Conditionals with Omitted Operands" to create a wrapper macro for your C function
#define somecstylefunction() (somecstylefunction() ? : "")
but in general case I would advise against that.
I suppose you could just add a wrapper function which tests for NULL, and returns an empty std::string. But more importantly, why are your C functions now returning NULL? What does a NULL pointer indicate? If it indicates a serious error, you might want your wrapper function to throw an exception.
Or to be safe, you could just check for NULL, handle the NULL case, and only then construct an std::string.
const char* s = somecstylefunction();
if (!s) explode();
std::string str(s);
For a portable solution:
(a) define your own string type. The biggest part is a search and replace over the entire project - that can be simple if it's always std::string, or big one-time pain. (I'd make the sole requriement that it's Liskov-substitutable for a std::string, but also constructs an empty string from an null char *.
The easiest implementation is inheriting publicly from std::string. Even though that's frowned upon (for understandable reasons), it would be ok in this case, and also help with 3rd party libraries expecting a std::string, as well as debug tools. Alternatively, aggegate and forward - yuck.
(b) #define std::string to be your own string type. Risky, not recommended. I wouldn't do it unless I knew the codebases involved very well and saves you tons of work (and I'd add some disclaimers to protect the remains of my reputation ;))
(c) I've worked around a few such cases by re-#define'ing the offensive type to some utility class only for the purpose of the include (so the #define is much more limited in scope). However, I have no idea how to do that for a char *.
(d) Write an import wrapper. If the C library headers have a rather regular layout, and/or you know someone who has some experience parsing C++ code, you might be able to generate a "wrapper header".
(e) ask the library owner to make the "Null string" value configurable at least at compile time. (An acceptable request since switching to 0 can break compatibility as well in other scenarios) You might even offer to submit the change yourself if that's less work for you!
You could wrap all your calls to C-stlye functions in something like this...
std::string makeCppString(const char* cStr)
{
return cStr ? std::string(cStr) : std::string("");
}
Then wherever you have:
std::string imacppstring = somecstylefunction();
replace it with:
std::string imacppstring = makeCppString( somecystylefunction() );
Of course, this assumes that constructing an empty string is acceptable behavior when your function returns NULL.
I don't generally advocate subclassing standard containers, but in this case it might work.
class mystring : public std::string
{
// ... appropriate constructors are an exercise left to the reader
mystring & operator=(const char * right)
{
if (right == NULL)
{
clear();
}
else
{
std::string::operator=(right); // I think this works, didn't check it...
}
return *this;
}
};
Something like this should fix your problem.
const char *cString;
std::string imacppstring;
cString = somecstylefunction();
if (cString == NULL) {
imacppstring = "";
} else {
imacppstring = cString;
}
If you want, you could stick the error checking logic in its own function. You'd have to put this code block in fewer places, then.