Annoying C++ gcc warning message - c++

I've written the following program to match regular expressions in C++
#include <regex.h>
#include <iostream>
using namespace std;
/*
* Match string against the extended regular expression in
* pattern, treating errors as no match.
*
* return true for match, false for no match
*/
bool match(const char *string, char *pattern)
{
int status; regex_t re;
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0)
return false;
/* report error */
status = regexec(&re, string, (size_t) 0, NULL, 0);
regfree(&re);
if (status != 0) {
return false; /* report error */
}
return true;
}
int main()
{
string str = "def fadi 100";
bool matchExp = match(str.c_str(), "^[Dd][Ee][Ff][' '\t]+[A-z]+([,])?[''\t]+[0-9]+$");
cout << (matchExp == true ? "Match": "No match") << endl;
}
The program works fine just as expected, but when I compile the code using gcc with the -Wall -Werror arguments (Linux environment), I get a very annoying warning message saying the following:
main.cpp: In function ‘int main()’:
main.cpp:33:90: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Is there a way to force the compiler to believe that str.c_str() is the same as char * str? if so, how?

No, there isn't. That conversion was deprecated in C++03 and is illegal in C++11; don't do it.
Deprecation of that conversion comes from the fact that string literals are read-only, hence const; accessing them using a pointer to non-const char could possibly lead to modifying const objects, hence invoking undefined behavior. The warning isn't annoying; it is meant to save you from possibly crashing your application - or worse.
Also, you are wrong in reading the warning message; it isn't about c_str(), it is about passing string literal as char *.
The only way to really fix your code is to change second parameter of your match to be const char *, not char *, and copy the passed string to a new, buffer, internal to that function (why not in main()? Because with internal buffer, you have less boilerplate on the caller's side).
I'd also like to suggest totally different solution, since the question is tagged "C++": Boost.Regex.

Is there a way to force the compiler to believe that str.c_str() is the same as char * str?
That's actually not the issue here - you are already passing str.c_str() as a const char*.
The issue is that the second parameter is (also) a string literal, but has type char*. Try changing the second parameter to const char*.
If that still raises errors (due to the regex.h functions not specifying the correct const-ness), you're going to have to do something like this in main() or match():
char pattern[] = "^[Dd][Ee]...etc";
bool matchExp = match(str.c_str(), pattern);
See here for the reason why.

The problem is that a string literal should be only assigned to a pointer of a const char, so you need to change match to take a char const* pattern (which should be possible when you pass a string literal)

Make 2 parameter of function match const char *, warning is because of it

Related

why it cannot convert char* to char

In c++ we can write
1 char *s="hello"
but the below lines of program produces an error ( cannot convert char* to char)
2 char *s;
*s="hello";
I am confused here, what is difference between 1 and 2
why this error is coming?
In C++, a string literal is a constant array of characters, not just an array of characters like in C. Anyways, to assign to such a variable (Which is best avoided), you do not have to dereference the pointer. Dereferencing it accesses the first element, which is just a char. A char cannot hold an array of characters inside it, causing an error. This is more the reason why you should be using std::string.
Some compilers such as GCC provide extensions to make such code possible since it is not standards compliant code, and it would look like:
char* s = "hello";
s = "new string";
This generates the following warning in GCC (But still gets the expected result):
warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
Clang also has the same behavior with the same output (Also generating a warning)
A string is an array of characters. The start of a string therefore is const char *.
Therefore to reference a string, you can use const char * s = "hello";
However if you dereference a const char*, you get a const char. This isn't a string i.e. *s gives you 'h'.
In your code *s="hello";, you are saying "assign at the dereferened s the value "hello"". Dereferencing s is a character only, to which you are trying to assign a string.
The problem is the second asterisk in your second example.
The first code is this
char *s="hello";
The equivalent code is this
char *s;
s="hello";
No * before s in the second line.
Now as everyone is pointing out neither of these are legal C++. The correct code is
const char *s="hello";
or
const char *s;
s="hello";
Because string literals are constant, and so you need a pointer to const char.
I am confused here, what is difference between 1 and 2 why this error is coming?
As many others * in C++ means different things in different context:
char *s; // * here means that s type is a pointer to char, not just char
*s; // in this context * means dereference s, result of exression is char
int a = 5 * 2; // in this context * means multiply
so case 1 and 2 may look similar to you but they mean very different things hence the error.

String copy using pointers in c++, during the copy the program is crashing

I am getting an error while copying one string to another string using pointers.
#include<iostream>
#include<string>
using namespace std;
void String_copy(char* scr,char* des)
{
while(*scr!='\0')
{
*des= *scr;
scr++;
des++;
}
}
int main()
{
char *str1, *str2;
str1="bharath";
str2="ygftygyfrgtg";
String_copy(str1,str2);
cout<<str1<<endl;
cout<<str2<<endl;
system("pause");
return 0;
}
In below code you have undefined behaviour:
char *str1, *str2;
str1="bharath";
str2="ygftygyfrgtg";
you should assign string literals only to const* char, this also means you should not modify str and str2
you can fix above with:
char str1[] = "bharath";
char str2[] = "ygftygyfrgtg";
but you must also fix String_copy - so that it checks bounds of arrays being modified, ie. add additional parameter with max length of des, also dont forget to add '\0` at the end.
First of all ISO C++ forbids converting string constants to char* pointers.
Try something like this instead to define str1 and str2:
char str1[]="bharath";
char str2[]="ygftygyfrgtg";
Your second problem is the String_copy function, where you just check one of the strings for the terminal \0 character. Also you should add a \0 to the des string (in case it was initially longer):
Something like this will work:
void String_copy(char* scr,char* des){
while(*scr!='\0' && *des!='\0')*des++=*scr++;
*des=0;
}
Note that you can copy maximally up to the length of your shorter string, since you did not allocate more memory anywhere.
Also if it is possible you should use std::string
The two strings are different lengths but you only check for a zero terminator in one of them. Either use strings of equal length or check for the zero terminator in both (and decide what to do with the excess characters).
The problem is that "bharath" is not of type char*.
Its actually a type char const* but the language (for comapability with C) allows auto conversion between the two. If you turn on your warnings (and treat them as errors) this will not even be allowed to compiler:
> g++ -std=c++11 -Wall -Wextra -Werror sc.cpp
sc.cpp:36:10: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
str1="bharath";
Now (that you have fixed this) you are suffering from the issue that the destination string could be shorter than src. Which will result in the same problem (writing to memory you dont own).

Depreciated conversion from string constant to 'char*'

I hope someone can help me. I'm converting a C language program to C++ in order to easily use strings but when I go to compile, I get this error:
inventory.cpp:225: warning: depreciated conversion from string constant to 'char*'
This is where the code in question:
#define FNAME "database.dat"
// test data struct
struct t_Record
{
int number;
char word[100];
//String word[];
} Record;
int main (void)
{
int Rec = 0; // record number
FILE *File;
srand(time(NULL));
File = FileOpen(FNAME);
if (!File)
{
printf("Error hommie!\n\n");
exit(-1);
}
...etc.
This is where the compiler tells me the error occurred:
File = FileOpen(FNAME);
I just don't see what is wrong...
The place where the compiler tell me to look doesn't even have a string or char associated with it??
Now I understand this error has been seen before, but my question is specific to my code.
The problem is that you are trying to convert a string literal (with type const char[]) to char*.
The place where the compiler tell me to look doesn't even have a
string or char associated with it??
Yes, it is on the top of the file:
#define FNAME "database.dat"
C++ Standard n3337 § 2.14.5/1
String literals
A string literal is a sequence of characters (as defined in 2.14.3)
surrounded by double quotes, optionally prefixed by R, u8, u8R, u, uR,
U, UR, L, or LR, as in "...", R"(...)", u8"...", u8R"(...)", u"...",
uR"* ̃(...)* ̃", U"...", UR"zzz(...)zzz", L"...", or LR"(...)",
respectively.
You can avoid the warning by casting to char*:
File = FileOpen( (char*)FNAME);
Even better modify FileOpen to accept a const char*. This will be more safe and just right as you don't intend to modify the string.
As #lizusek said, you can avoid the warning by type casting to char*, but even better would be to rewrite your code to avoid type casting. While it can work and solve a lot of headaches, it can be very dangerous if you type cast the wrong things.

g++ strstr says invalid conversion from const char * to char *

I am converting a project written in C++ for windows. Everything is going fine (meaning I clearly see what needs to be changed to make things proper C++) until I hit this, which is my own little routine to find a keyword in along string of keyword=value pairs:
bool GetParameter(const char * haystack, const char *needle) {
char *search, *start;
int len;
len = strlen(needle) + 4; // make my own copy so I can upper case it...
search = (char *) calloc(1,len);
if (search == NULL) return false;
strcpy(search,needle);
strupr(search);
strcat(search,"="); // now it is 'KEYWORD='
start = strstr(haystack,search); <---- ERROR from compiler
g++ is telling me "Invalid conversion from const char * to char * "
(the precise location of the complaint is the argument variable 'search' )
But it would appear that g++ is dyslexic. Because I am actually going the other way. I am passing in a char * to a const char *
(so the conversion is "from char * to const char *" )
The strstr prototype is char * strstr(const char *, const char *)
There is no danger here. Nothing in any const char * is being modified.
Why is it telling me this?
What can I do to fix it?
Thanks for any help.
The background to the problem is that C defines the function strstr as:
char* strstr(const char*, const char*);
This is because C doesn't allow overloaded functions, so to allow you to use strstr with both const and non-const strings it accepts const strings and returns non-const. This introduces a weakness in C's already fragile type-system, because it removes const-ness from a string. It is the C programmer's job to not attempt to write via a pointer returned from strstr if you pased in non-modifiable strings.
In C++ the function is replaced by a pair of overloaded functions, the standard says:
7. The function signature strstr(const char*, const char*) shall be replaced by the two declarations:
const char* strstr(const char* s1, const char* s2);
char* strstr( char* s1, const char* s2);
both of which shall have the same behavior as the original declaration.
This is type-safe, if you pass in a const string you get back a const string. Your code passes in a const string, so G++ is following the standard by returning a const string. You get what you asked for.
Your code compiles on Windows because apparently the standard library you were using on Windows doesn't provide the overloads and only provides the C version. That allows you to pass in const strings and get back a non-const string. G++ provides the C++ versions, as required by the standard. The error is telling you that you're trying to convert the const return value to a non-const char*. The solution is the assign the return value to a const char* instead, which is portable and compiles everywhere.
Error is not regarding the arguments to stsrtr. Compiler is complaining about the conversion of the 'const char *' returned by strstr. You can't assign it to *start which is just char *
You can try one of these:
const char *start;
or
string start(strstr(haystack,search));
Although declaring start as const char* might suffice, what seems more appropriate to me is to use std::string objects instead:
#include <string>
#include <cctype>
#include <algorithm>
bool GetParameter(const char * haystack, const char *needle) {
std::string hstr(haystack), nstr(needle);
std::transform(nstr.begin(), nstr.end(),nstr.begin(), ::toupper);
nstr += "=";
std::size_t found = hstr.find(nstr);
if (found != std::string::npos) {
... // "NEEDLE=" found
}
else {
...
}
...
}
The conversion it is complaining about is from strstr(...) to start. Change the declaration of start to const char* start;
you can use such like:
start = const_cast<char *>(strstr( haystack, static_cast<const char *>(search) ));

C++ deprecated conversion from string constant to 'char*'

I have a class with a private char str[256];
and for it I have an explicit constructor:
explicit myClass(char *func)
{
strcpy(str,func);
}
I call it as:
myClass obj("example");
When I compile this I get the following warning:
deprecated conversion from string constant to 'char*'
Why is this happening?
This is an error message you see whenever you have a situation like the following:
char* pointer_to_nonconst = "string literal";
Why? Well, C and C++ differ in the type of the string literal. In C the type is array of char and in C++ it is constant array of char. In any case, you are not allowed to change the characters of the string literal, so the const in C++ is not really a restriction but more of a type safety thing. A conversion from const char* to char* is generally not possible without an explicit cast for safety reasons. But for backwards compatibility with C the language C++ still allows assigning a string literal to a char* and gives you a warning about this conversion being deprecated.
So, somewhere you are missing one or more consts in your program for const correctness. But the code you showed to us is not the problem as it does not do this kind of deprecated conversion. The warning must have come from some other place.
The warning:
deprecated conversion from string constant to 'char*'
is given because you are doing somewhere (not in the code you posted) something like:
void foo(char* str);
foo("hello");
The problem is that you are trying to convert a string literal (with type const char[]) to char*.
You can convert a const char[] to const char* because the array decays to the pointer, but what you are doing is making a mutable a constant.
This conversion is probably allowed for C compatibility and just gives you the warning mentioned.
As answer no. 2 by fnieto - Fernando Nieto clearly and correctly describes that this warning is given because somewhere in your code you are doing (not in the code you posted) something like:
void foo(char* str);
foo("hello");
However, if you want to keep your code warning-free as well then just make respective change in your code:
void foo(char* str);
foo((char *)"hello");
That is, simply cast the string constant to (char *).
There are 3 solutions:
Solution 1:
const char *x = "foo bar";
Solution 2:
char *x = (char *)"foo bar";
Solution 3:
char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");
Arrays also can be used instead of pointers because an array is already a constant pointer.
Update: See the comments for security concerns regarding solution 3.
A reason for this problem (which is even harder to detect than the issue with char* str = "some string" - which others have explained) is when you are using constexpr.
constexpr char* str = "some string";
It seems that it would behave similar to const char* str, and so would not cause a warning, as it occurs before char*, but it instead behaves as char* const str.
Details
Constant pointer, and pointer to a constant. The difference between const char* str, and char* const str can be explained as follows.
const char* str : Declare str to be a pointer to a const char. This means that the data to which this pointer is pointing to it constant. The pointer can be modified, but any attempt to modify the data would throw a compilation error.
str++ ; : VALID. We are modifying the pointer, and not the data being pointed to.
*str = 'a'; : INVALID. We are trying to modify the data being pointed to.
char* const str : Declare str to be a const pointer to char. This means that point is now constant, but the data being pointed too is not. The pointer cannot be modified but we can modify the data using the pointer.
str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
*str = 'a'; : VALID. We are trying to modify the data being pointed to. In our case this will not cause a compilation error, but will cause a runtime error, as the string will most probably will go into a read only section of the compiled binary. This statement would make sense if we had dynamically allocated memory, eg. char* const str = new char[5];.
const char* const str : Declare str to be a const pointer to a const char. In this case we can neither modify the pointer, nor the data being pointed to.
str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
*str = 'a'; : INVALID. We are trying to modify the data pointed by this pointer, which is also constant.
In my case the issue was that I was expecting constexpr char* str to behave as const char* str, and not char* const str, since visually it seems closer to the former.
Also, the warning generated for constexpr char* str = "some string" is slightly different from char* str = "some string".
Compiler warning for constexpr char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *const'
Compiler warning for char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.
Tip
You can use C gibberish ↔ English converter to convert C declarations to easily understandable English statements, and vice versa. This is a C only tool, and thus wont support things (like constexpr) which are exclusive to C++.
In fact a string constant literal is neither a const char * nor a char* but a char[]. Its quite strange but written down in the c++ specifications; If you modify it the behavior is undefined because the compiler may store it in the code segment.
Maybe you can try this:
void foo(const char* str)
{
// Do something
}
foo("Hello")
It works for me
I solve this problem by adding this macro in the beginning of the code, somewhere. Or add it in <iostream>, hehe.
#define C_TEXT( text ) ((char*)std::string( text ).c_str())
I also got the same problem. And what I simple did is just adding const char* instead of char*. And the problem solved. As others have mentioned above it is a compatible error. C treats strings as char arrays while C++ treat them as const char arrays.
For what its worth, I find this simple wrapper class to be helpful for converting C++ strings to char *:
class StringWrapper {
std::vector<char> vec;
public:
StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
}
char *getChars() {
return &vec[0];
}
};
The following illustrates the solution, assign your string to a variable pointer to a constant array of char (a string is a constant pointer to a constant array of char - plus length info):
#include <iostream>
void Swap(const char * & left, const char * & right) {
const char *const temp = left;
left = right;
right = temp;
}
int main() {
const char * x = "Hello"; // These works because you are making a variable
const char * y = "World"; // pointer to a constant string
std::cout << "x = " << x << ", y = " << y << '\n';
Swap(x, y);
std::cout << "x = " << x << ", y = " << y << '\n';
}