Why do some libs use non-const char * as function argument? - c++

Sometimes using pure-C libs in my C++ projects, I see strange (in my opinion) function declarations.
E.g.: libldap's ldap_search_ext(): https://linux.die.net/man/3/ldap_search_ext_s
int ldap_search_ext(
LDAP *ld,
char *base,
int scope,
char *filter,
char *attrs[], // this one!
int attrsonly,
LDAPControl **serverctrls,
LDAPControl **clientctrls,
struct timeval *timeout,
int sizelimit,
int *msgidp );
Why can't attrs[] be a const char *?
Declarations like this don't want to change the content of the pointer and generate a lot of issues:
// pure C
void func(char * data[])
{
...
}
func({"blabla"}); // won't work (corrected: yes, this is wrong syntax, but it's true for structs of pointers)
const char *d[] = {"blabla", "blablu"};
func(d); // won't work
// C++
const std::string str("blabla");
char * data[] = { str.data() }; // even non-const won't work (because data() returns const*)
/// etc...
Is there any reason for not declaring such arguments as const?

This is mostly just (due to) a historical wart in the C standard that has never been fixed.
When const was added to C, the ability to implictly (and safely) convert simple pointers was added -- you can implicitly convert a T * to a const T * just fine. However, (safe) conversion of more complex pointer types was missed -- you can't convert a T * const * to a const T * const *. As a result, when a library takes a double pointer like this, it does not have any 'good' way of making it const if it is read only. Making it either a const char ** or a const char * const * would break some uses (requiring messy explicit casts).
Note that allowing implicit conversions of T ** to const T ** would be unsafe -- such a pointer could be used to modify a T * to point at a const T * without a cast.

One likely reason is that string constants in C (unlike C++) are not const.
As such, there was a historical lack of const-correctness in many libraries that should have been there. Had string constants been const, programmers would have been forced to account for it.
When dealing with libraries such as this that you know don't modify the argument, you have to apply a const_cast to make it fit.
char *d[] = {const_cast<char *>("blabla"), const_cast<char *>("blablu")};
func(d);
const std::string str("blabla");
char * data[] = { const_cast<char *>(str.data()) };
func(data);

Related

If buffer of bytes should be unsigned char do I have to keep casting all the time?

According to these answers a buffer of bytes should be unsigned char, either because of convention or maybe the padding guarantees, I'm not sure. I have a function that looks something like:
saveDataToFile(const unsigned char* data, size_t size);
I find that I keep having to cast when I have a vector of char or an std::string or a string literal or something, and my code ends up looking like:
const char* text = "text";
saveDataToFile(text, 4); // Argument of const char* is incompatible with parameter of type const unsigned char*
saveDataToFile(reinterpret_cast<const unsigned char*>(text), 4);
Is there a way to avoid doing this all the time? Someone once mentioned to make my function take const char* instead of unsigned, but that doesn't really as then I'd have to cast the other way. For example std::string has .c_str() and .data() that return signed and unsigned. I also thought about taking void*, maybe that's the best way?
Perhaps the simplest way, as you have suggested yourself, is to make the function's first argument a const void* and then cast that to whatever is needed inside the function. This way, you also avoid using a reinterpret_cast and can safely use a static_cast:
void saveDataToFile(const void* data, size_t size)
{
const uint8_t* local = static_cast<const uint8_t*>(data);
//.. do something with the cast pointer ...
}
int main()
{
double dData = 33.3;
int16_t sData = 42;
char cData[] = "Hello, World!";
saveDataToFile(&dData, sizeof(dData));
saveDataToFile(&sData, sizeof(sData));
saveDataToFile(cData, sizeof(cData));
return 0;
}
A more "Pure C++" way (in some folks' eyes, maybe) would be to make a templated function. However, the disadvantages here are: (a) you will need a reinterpret_cast in this case; and (b) the compiler will (probably) generate separate function code for each of the different argument types used:
template<typename T>
void saveDataToFile(const T* data, size_t size)
{
const uint8_t* local = reinterpret_cast<const uint8_t*>(data);
//.. do something with the cast pointer ...
}

A value of type "const char*" cannot be used to initialize an entity of type "char *"

I have a code like this but I keep receiving this error :
A value of type "const char*" cannot be used to initialize an entity of type "char *"
What is going on?
I have read up on the following threads but have not been able to see any result to my answer as all of them are either from char to char* or char* to char:
Value type const char cannot be used to initialize an entity of type char*
Value of type char* cannot be used to initialize an entity of type "char"
#include <iostream>;
using namespace std;
int main() {
int x = 0; //variable x created
int cars (14);//cars is created as a variable with value 14
int debt{ -1000 };//debt created with value 1000
float cash = 2.32;
double credit = 32.32;
char a = 'a';//for char you must use a single quote and not double
char* sandwich = "ham";
return 0;
}
I am using Visual Studio Community 2017
That is correct. Let’s say you had the following code:
const char hello[] = "hello, world!";
char* jello = hello; // Not allowed, because:
jello[0] = 'J'; // Undefined behavior!
Whoops! A const char* is a non-const pointer to const char. If you assign its value to a non-const char*, you’ve lost its const property.
A const pointer to non-const char would be a char* const, and you can initialize a char* from that all day if you want.
You can, if you really want, achieve this with const_cast<char*>(p), and I occasionally have, but it’s usually a sign of a serious design flaw. If you actually get the compiler to emit instructions to write to the memory aliased by a string constant, you get undefined behavior. One of the many things that might go wrong is that some implementations will store the constant in read-only memory and crash. Or the same bytes of memory might be re-used for more than one purpose, because after all, we warned you never to change it.
By the way, the rules in C are different. This is solely for backward-compatibility with early versions of C that did not have the const keyword, and you should never write new code that uses a non-const alias to a string constant.
You need to make your string literal type const because in C++ it is a constant array of char, unlike C where it is just an array of char. You cannot change a string literal, so making it const is preferred in C++ for extra safety. It is the same reason you have to use an explicit cast when going from const char* to char*. It's still technically "allowed" in C++ since it is allowed in C, which is why it's just a warning. It's still bad practice to do so. To fix the warning, make it const.
const char* sandwich = "ham";
Your code (and underlying assumption) is valid pre C++11 standard.
String literals (e.g. "ham") since C++11 are of type const char* (or const char[]) if you will instead of char * they used to be. [Always read specs for breaking changes!!!]
Hence the warning in VS 2017. Change the compiler version to pre C++11 version and you will be amazed.
This has subtle nuances and can cause frustrating debug sessions
// C++11 or later
auto c = "Rowdie";
// c has type const char*, can't use c to modify literal
c[0] = 'H'; // illegal - CTE
// -vs-
char * d = "Rowdie";
d[0] = 'H';
cout << d; // outputs "Howdie"
Also another example is auto return type from functions
auto get_literal() {
// ... function code
return "String Literal";
}
// and using value later
char* lit = get_literal(); // You get same error as const char* cannot be init to char*

Why is the second argument of the strtod function a non-const pointer? [duplicate]

The standard C library functions strtof and strtod have the following signatures:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
They each decompose the input string, str, into three parts:
An initial, possibly-empty, sequence of whitespace
A "subject sequence" of characters that represent a floating-point value
A "trailing sequence" of characters that are unrecognized (and which do not affect the conversion).
If endptr is not NULL, then *endptr is set to a pointer to the character immediately following the last character that was part of the conversion (in other words, the start of the trailing sequence).
I am wondering: why is endptr, then, a pointer to a non-const char pointer? Isn't *endptr a pointer into a const char string (the input string str)?
The reason is simply usability. char * can automatically convert to const char *, but char ** cannot automatically convert to const char **, and the actual type of the pointer (whose address gets passed) used by the calling function is much more likely to be char * than const char *. The reason this automatic conversion is not possible is that there is a non-obvious way it can be used to remove the const qualification through several steps, where each step looks perfectly valid and correct in and of itself. Steve Jessop has provided an example in the comments:
if you could automatically convert char** to const char**, then you could do
char *p;
char **pp = &p;
const char** cp = pp;
*cp = (const char*) "hello";
*p = 'j';.
For const-safety, one of those lines must be illegal, and since the others are all perfectly normal operations, it has to be cp = pp;
A much better approach would have been to define these functions to take void * in place of char **. Both char ** and const char ** can automatically convert to void *. (The stricken text was actually a very bad idea; not only does it prevent any type checking, but C actually forbids objects of type char * and const char * to alias.) Alternatively, these functions could have taken a ptrdiff_t * or size_t * argument in which to store the offset of the end, rather than a pointer to it. This is often more useful anyway.
If you like the latter approach, feel free to write such a wrapper around the standard library functions and call your wrapper, so as to keep the rest of your code const-clean and cast-free.
Usability. The str argument is marked as const because the input argument will not be modified. If endptr were const, then that would instruct the caller that he should not change data referenced from endptr on output, but often the caller wants to do just that. For example, I may want to null-terminate a string after getting the float out of it:
float StrToFAndTerminate(char *Text) {
float Num;
Num = strtof(Text, &Text);
*Text = '\0';
return Num;
}
Perfectly reasonable thing to want to do, in some circumstances. Doesn't work if endptr is of type const char **.
Ideally, endptr should be of const-ness matching the actual input const-ness of str, but C provides no way of indicating this through its syntax. (Anders Hejlsberg talks about this when describing why const was left out of C#.)

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) ));

How to convert const char* to char*

can any body tell me how to conver const char* to char*?
get_error_from_header(void *ptr, size_t size, size_t nmemb, void *data) {
ErrorMsg *error = (ErrorMsg *)data;
char* err = strstr((const char *)ptr,"550");
//error cannot convert const char** to char*
if(err) {
strncpy(error->data,(char*)ptr,LENGTH_ERROR_MESSAGE-1);
error->data[LENGTH_ERROR_MESSAGE-1] = '\0';
error->ret = true;
}
return size*nmemb;
}
There are a few things I don't understand here. I see that this is tagged for C++/CLI, but what I describe below should be the same as Standard C++.
Doesn't compile
The code you give doesn't compile; get_error_from_header does not specify a return type. In my experiments I made the return type size_t.
Signature of C++ strstr()
The signature for strstr() in the standard C library is:
char *
strstr(const char *s1, const char *s2);
but the signature for strstr() in the C++ library, depending on the overload, is one of:
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
I would choose the first overload, because you don't want to modify the string, you only want to read it. Therefore you can change your code to:
const char* err = strstr((const char *)ptr, "550");
if (err != NULL) {
...
}
Also, I'm assuming your comment reporting the error:
//error cannot convert const char** to char*
is a typo: there's no const char** to be seen.
Assignment to err unnecessary
As is pointed out in a previous answer, the use of err to store the result of strstr is unnecessary if all it's used for is checking NULL. Therefore you could use:
if (strstr((const char *)ptr, "550") != NULL) {
...
}
Use of reinterpret_cast<> encouraged
As is pointed out in another answer you should be using reinterpret_cast<> instead of C-style casts:
if (strstr(reinterpret_cast<const char *>(ptr), "550") != NULL) {
...
}
Use of const_cast<> to strip const
Given the example in the question, I don't see where this is necessary, but if you had a variable that you need to strip of const-ness, you should use the const_cast<> operator. As in:
const char * p1;
char * p2;
p2 = const_cast<char *>(p1);
As is pointed out in a comment, the reason to use const_cast<> operator is so that the author's intention is clear, and also to make it easy to search for the use of const_cast<>; usually stripping const is the source of bugs or a design flaw.
You don't appear to use err in the rest of that function, so why bother creating it?
if (NULL != strstr((const char *)ptr, "550"))
{
If you do need it, will you really need to modify whatever it points to? If not, then declare it as const also:
const char* err = strstr((const char *)ptr, "550");
Finally, as casts are such nasty things, it is best to use a specific modern-style cast for the operation you want to perform. In this case:
if (NULL != strstr(reinterpret_cast<const char *>(ptr), "550"))
{
Can't you just do:
char* err = strstr((char *)ptr,"550");
The error is because if you pass in a const char* to strstr you get one out (because of the overload).
//try this instead:
const char* mstr="";
char* str=const_cast<char*>(mstr);
Well is ptr (which you passed in as void*) actually const or not? (In other words, is the memory under your control?) If it's not, then cast it to char* instead of const char* when calling strstr. If it is, however, you'll get a const char* out (pointing to a location inside of the string pointed to by ptr), and will then need to strncpy out to another string which you are responsible for managing.
According to my deep research I have found numerous forums that have no direct solution or a reference answer to this question, I then delve into the GCC online documentation giving a brief read for their compiler properly docs and this is what I can provide.
In GNU C, pointers to arrays with qualifiers work similar to pointers to other qualified types. For example, a value of type int ()[5] can be used to initialize a variable of type const int ()[5]. These types however aren't compatible in ISO C because the const qualifier is formally attached to the element type of the array and not the array itself.
This description might be better understood if we take this
extern void
transpose (int N, int M, double out[M][N], const double in[N][M]);
double x[3][2];
double y[2][3];
…
transpose(3, 2, y, x);
Observing the above is that if you had an
s1=createStudent(s1, 123, "Poli");
s2=createStudent(s2, 456, "Rola);
Whereas the const char[5] for both "Poli" and "Rola" have correlation to a char a[]. It is strictly not permitted as each element has the qualifier attached and not the entire array as a const.