I'm using some C Leagacy Code within a C++ project.
On used C function looks like this
void Add_To_log(const * const char pString_1, const * const char pString_2, int number);
Now when I call this Functions from C++ Code like this
foo()
{
Add_To_log("my first string", "my second string", 2);
}
I get a compiler warning ISO C++ Forbids converting string to char.
So to get rid of this i thought of creating a c++ wrapper with string_view to avoid unnecessary coping of my strings
void CPP_Wrapper(const string_view& string1, const string_view& string2, int number)
{
Add_To_log(string1, string2, 2);
}
Now if i understood the reference correctly string_view does not necessarily contain a terminating null character with is essential for all c functions because it does not own the string object. It simply displays it.
However can i assume in my particular case that string1 and string2 are null terminated?
However can i assume in my particular case that string1 and string2 are null terminated?
No. You should not assume that a string view is null terminated. The wrapper function that you suggest is counter productive, if the C function expects a null-terminated string.
On used C function looks like this
void Add_To_log(const * const char pString_1, const * const char pString_2, int number);
That declaration is ill-formed. If you fix it to be something like:
void Add_To_log(const char * const pString_1, const char * const pString_2, int number)
then this call is well-formed:
Add_To_log("my first string", "my second string", 2); // No problem
std::string already has functions to provide a pointer to older C library functions
http://www.cplusplus.com/reference/string/string/data/
These provide a non-owning, read only pointer suitable to most C library functions that need read only access during the function call. I'm assuming the std::string has a greater lifetime than the function call, and that the pointer is used only during the function call. Or as the documentation I linked above states, "The pointer returned may be invalidated by further calls to other member functions that modify the object." (including the destructor obviously)
Also, take care to use c_str() in c++98 builds, as data() doesn't guarantee the terminating null until c++11, as noted in the documentaion link and by eerorika.
#include <stdio.h>
#include <string>
extern "C" {
void legacy_logger(const char * const pstr) {
printf("%s\n", pstr);
}
}
int main()
{
std::string message{ "This is the string." };
legacy_logger(message.data());
}
Related
So I got this code from my teacher but it doesn`t work combined with other code, it works only if it is separatly in a project. The whole code works great, less this part
"Notes" is an other class which works perfectly
class student
{
char name[30];
notes marks;
public:
student(int = 8, char* =" "); //HERE IS WHERE I GOT THE PROBLEM, AT HIS CHAR*
~student();
void read_name();
void read_marks();
void modif_mark(int, double);
void print();
void check_marks();
};
/*...
...
...
*here is a lot of code working great*
...
...
...
*/
student::student(int nr_marks, char* sir) :
marks(nr_marks)
{
strcpy_s(name, sir);
}
Depending on compiler, C-style string literals may be allocated in readonly memory. Thus they are const char[N+1] (N is the string length) (which is implicitly convertible to const char* because of array to pointer decay).
The problem you're having is that it's illegal to drop const qualifiers (with the exception of the infamous const_cast or equivalent C-style cast).
Since you're only reading from sir, you can fix this by making sir be const char* instead, which doesn't violate const:
class student {
...
student(int = 8, const char* =" "); // problem solved
...
};
student::student(int nr_marks, const char* sir) : // remember to change it here as well
marks(nr_marks)
{
strcpy(name, sir);
}
About string literals:
In C, string literals are of type char[], and can be assigned
directly to a (non-const) char*. C++03 allowed it as well (but
deprecated it, as literals are const in C++). C++11 no longer allows
such assignments without a cast.
Your teacher is possibly more versed in C or "dated" C++. As stated above the language (= modern C++) disallows the assignment / initialization of a char* from a string literal.
Workarounds:
Use char const * as type for the parameter. That's the reasonable solution when the string is not modified (why would you modify a string literal??)
Not recommended. When you need to write to that pointer: Store (a copy of) the string literal as a (non const) char[] and reference that. Issues: thread safety; side effects; why would you want to do this??
Better. If you need to write to / change the string: use std::string.
Below is the error version
print_results("C = ", c);
Below is the Solved Version
print_results((char*)"C = ", c);
I have a struct as below
struct st
{
std::string name;
std ::string refer;
int number;
std::string path;
};
Have created array of above structure as
struct st var[5]={{"rick1","ross1",1,"demo1"},
{ "rick2","roos2",2,"demo2" },
{ "rick3","roos3",3,"demo3"},
{"rick4","roos4,4,"demo4"},
{"rick5","roos5",5,"demo5"}};
Now i called my userdefine function (pass) as
c++ code
for(i=0;i<5;i++)
pass(var[i].name.c_str());// how can i pass name sting to char *?
c code
void pass(char *name) // implemented in c code so cannot use string
{
cout<<name<<endl;
}
I m supposed to pass name which is string type in calling function(c++ code) to called function(c code) which is char * type .I m using c_str() but it throw an error .Please help me out thanks in advance
Note: pass function is called from c++ code which pass string as an argument to c code which catch as char *
name.c_str() returns a const char*. You can't pass a const pointer as an argument for a function taking a non-const pointer.
If you have a very recent compiler, you may be able to use std::string::data() which has a non-const overload since the C++17 standard.
Otherwise you would need a const_cast:
pass(const_cast<char*>(var[i].name.c_str()))
I'm assuming here that the pass function does not actually modify the string.
What is the difference between the line that does not compile and the line that does compile?
The line that does not compile gives this warning: deprecated conversion from string constant to 'char*'
Also, I'm aware casting (char *) on the string being passed in to the function would solve the problem, but I would like to understand why that's even necessary when the 2nd line compiles just fine.
class Student {
public:
Student( char name[] ) {
}
}
int main() {
Student stud( "Kacy" ); //does not compile
char name[20] = "Kacy"; //compiles just fine
}
The char[] signature in the parameter is exactly the same as char*. In C++, it is illegal to convert a string constant char const* (the string "Kacy") to a char* because strings are immutable.
Your second example compiles because the name is an actual array. There is no change to char*.
As a solution, change your parameter to take a const string array:
Student(char const name[]);
which again is the same as
String(char const *name);
though you're better off using std::string:
#include <string>
class String
{
public:
String(std::string name);
};
C++ string literals have type "array of n const char", which decays into const char * in your use case. The implicit conversion to char * (that is, discarding the const) you're trying is deprecated, so there's a warning. Change the type in the constructor's signature or make an explicit const-cast.
From the C++ standard:
An ordinary string literal has type "array of n const char" and static storage duration
The string
"Kacy"
is not an array of characters when the compiler produces the code. Instead, it will stash the string "Kacy" somewhere in memory, and produce a pointer to that place. So what you get is a const char * pointing at the string "Kacy\0".
If you change your constructor to:
Student(const char *nmae)
you can use it both as:
Student stud("Kacy");
and as this:
char name[20] = "Kacy";
Student stud2(name);
Note here that the compiler will generate code to FILL the array name with the characters in "Kacy", which is different from just usinv "Kacy" as an argument to the Student constructor.
I have encountered a function, such that it can differentiate between being called as
foo("bar");
vs
const char *bob = "bar";
foo(bob);
Possibilities I have thought of are:
Address of string: both arguments sat in .rdata section of the image. If I do both calls in the same program, both calls receive the same string address.
RTTI: no idea how RTTI can be used to detect such differences.
The only working example I could conjure up is:
void foo(char *msg)
{
printf("string literal");
}
void foo(const char *&msg)
{
printf("string pointer");
}
foo("bar"); // "string literal"
const char *soap = "bar";
foo(soap); // "string pointer"
I do not have access to the function's code, and the declarations in the header file only revealed one function declaration.
Here's another way to distinguish between a string literal and a pointer, based on the fact that string literals have array type, not pointer type:
#include <iostream>
void foo(char *msg)
{
std::cout << "non-const char*\n";
}
void foo(const char *&msg) // & needed, else this is preferred to the
// template function for a string literal
{
std::cout << "const char*\n";
}
template <int N>
void foo(const char (&msg)[N])
{
std::cout << "const char array reference ["<< N << "]\n";
}
int main() {
foo("bar"); // const char array reference [4]
}
But note that all of them (including your original function) can be "fooled" by passing something that isn't a string literal:
const char *soap = 0;
foo(soap);
char *b = 0;
foo(b);
const char a[4] = {};
foo(a);
There is no type in C++ which is unique to string literals. So, you can use the type to tell the difference between an array and a pointer, but not to tell the difference between a string literal and another array. RTTI is no use, because RTTI exists only for classes with at least one virtual member function. Anything else is implementation-dependent: there is no guarantee in the standard that string literals will occupy any particular region of memory, or that the same string literal used twice in a program (or even in a compilation unit) will have the same address. In terms of storage location, anything that an implementation can do with string literals, it is permitted also to do with my array a.
The function foo() in theory could use a macro to determine if the argument was a literal or not.
#define foo(X) (*#X == '"'
? foo_string_literal(X)
: foo_not_string_literal(X))
And what happens if you call it as:
const char bob[] = "bar";
foo(bob);
It's probably using some sort of distinction like that to make the determination.
EDIT: If there's only one function declaration in the header I can't conceive of any portable way the library could make that distinction.
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';
}