I have a simple question about GLib.
I have the following code:
static const char *words[] = { "one", "two", "three", NULL };
void main() {
puts(g_strjoinv("+", words));
}
This code prints one+two+three. It uses a GLib function which joins strings.
The signature of that function is:
char *g_strjoinv (const char *separator, char **str_array);
(To be exact, GLib uses gchar, not char, but let's ignore this.)
Now, I wonder why the parameter is char **str_array and not const char **str_array. It forces me to do an explicit cast to get rid of the compiler's warning ("expected 'char **' but argument is of type 'const char **'"):
puts(g_strjoinv("+", (char **)words));
I look in GLib's reference and I see that all the functions there are defined this way: they accept char **, not const char **.
Why is that? Why doesn't GLib use const char **?
The need to use an explicit cast to get rid of the const makes my code less safe (because the compiler no longer checks the arguments' compatibility). It also makes me nervous because GLib doesn't "sign a contract" that say it won't change my data.
The assumption in your question is that if the second argument of g_strjoinv() was declared as type const char **, then you can just as easily pass either a const char ** or a char ** to it.
Unfortunately, this isn't true. As explained in this question from the comp.lang.c FAQ, using a pointer to T (for any type T) where a pointer to const T is expected is OK, but only where the mismatch is at the top level of indirection. That is to say, you can pass a char * where a const char * is expected, but you cannot (without a cast) pass a char ** where a const char ** is expected, because in this case the mismatch is at the second level of indirection. The linked question explains in some detail why it works this way, which is "somewhat obscure".
So the upshot is there there is no type (in C) which will accept both a char ** and a const char ** without at least one of them requiring a cast. This being the case, there's probably not much reason to prefer either other than convenience, and the library authors apparently decided to go with the former. As a matter of pure speculation, I'd guess that wanting to pass a char ** is slightly more common than wanting to pass a const char **, and so the option they picked is probably more convenient.
In your case, you can just drop the const qualifier from the definition of your array. It might seem like bad form, if you like const, but since you have an array of pointers which point to string literals, your program is overwhelmingly likely to loudly complain and fail if anything attempts to write to them anyway, so you're not really losing safety in any meaningful way in this particular case. Even though it's undefined behavior to attempt to modify them, string literals have type array of char in C, not array of const char (unlike C++).
Slightly more obscure, but even if you could pass it as a const char **, the function here could still modify the pointers even if it couldn't modify what they point to, and just cause mayhem in a different way, so the promise the function made still wouldn't be guaranteeing that what you pass to the function wouldn't be changed in some way.
Related
Why does the following code raise no Warnings ?
Compiled with -Wall, -Wpedantic, -Wextra, and none of them raise a warning.
int main()
{
const char *p;
char a[] = "hey";
p = a;
(void) p;
return 0;
}
I would expect some kind of warning, such as assignment -Wdiscarded-qualifiers
You're assigning from a char * to a const char *. This is safe because you adding the const qualifier, not removing it.
If you did this:
char *p;
const char a[] = "hey";
p = a;
Then you would get a warning about discarding the const qualifier.
You are not discarding a qualifier. You're adding one. This feature is actually pretty important. It's one of those few cases where C actually offers a reasonable option for the programmer to protect himself from himself. For instance, have a look at the prototypes for string manipulation functions in the standard library:
char * strcpy ( char * destination, const char * source );
This gives us the information that destination will be altered, but source will not.
From comment below:
Will it also require that the destination parameter cannot be a const char *
There are ways around it so it's not required per se. We're talking C after all. But if you are planning to use an argument as an output argument it should not be declared as const. Here is an example where I'm using a const argument as output parameter. It's a function that sets the length of a string to zero:
// Note: Bad code. Do not do this at home. Ok, do it at home,
// but do not do it at work.
void removeString(const char * s)
{
char *p = (char*) s;
p[0] = 0;
}
But in order to do this, you first have to declare a pointer to non-const pointing to s, and then you have to add the cast (char*) to get rid of the warning. This is easy to do, but it's quite hard to do by mistake, so it serves as a pretty good protection.
Declaring an argument as a pointer to const gives two things:
It tells the programmer using the function that the function will not use the argument as an output argument, unless the author of the function is evil or doesn't know what he is doing.
It makes it harder (but not impossible) to change something you should not change by mistake in the function.
assignment from const char pointer to char pointer gives no warnings
Your example does something opposite. You assign the pointer to the constant object with the pointer to non constant object. So you do not discard anything hence no worning
strstr is a C99-conforming function, the type signature of which is the following:
char *strstr(const char *haystack, const char *needle);
Is it possible to implement this function without casting away a const somewhere?
For reference, here is Apple's implementation, and here is GNU's implementation. Both cast away the const at the end.
You can't implement strstr() without violating const correctness somehow. A cast is the most straightforward way to do that. You can probably hide the violation somehow (for example you could use memcpy() to copy the pointer value), but there's no point in doing so.
The problem is that strstr() takes a const char* that points to a string, and returns a non-const char* that points into the same string.
For example, this program:
#include <stdio.h>
#include <string.h>
int main(void) {
const char s[] = "hello";
char *result = strstr(s, "hello");
*result = 'H';
puts(result);
}
modifies (or at least attempts to modify) a const-qualified object, without using a pointer cast or any other obviously unsafe construct.
Back in 1989, the ANSI C committee could have avoided this problem by defining two different functions, say:
const char *strcstr(const char *haystack, const char *needle);
char *strstr ( char *haystack, const char *needle);
one that returns a pointer to a const char given a const arguments, and another that returns pointer to a modifiable char given a modifiable argument. (C++, which inherits the C standard library, does this by overloading.)
strstr() is one of several standard string functions that have this problem.
What you are seeing in case of strstr (and some other standard functions) is an idiomatic solution, whose intent is to support non-modifying operations on both const and non-const strings with a single function.
Yes, in order to implement such a function it necessary to explicitly cast away constness from the input pointer. Note that the cast by itself does not yet physically violate anything (meaning: it does not attempt to modify constant data and does not cause undefined behavior). Yet, it does open the door to such violations by returning a non-const pointer to const data to the caller, i.e. violates the conceptual rules of const-correctness.
An alternative solution would be to provide two versions of the same standard function - a const one and a non-const one - but without C++-style function overloading this would require two distinctive function names, which does not necessarily look like a very good idea (and even with C++-style function overloading it has its issues too).
In this case it is effectively the responsibility of the caller to receive the result into a pointer of the same type as the one that was passed in as an argument. If the argument pointer was const-qualified, it is a very good programming practice to receive the result into a pointer that is const-qualified as well. As long as this guideline is observed, this idiom actually feels right at home in the realm of C language.
In my plain C99 project, I have an external C library that defines an interface (via GObject interfaces) that I need to implement:
void interface_function (const char *address, [...]);
Now, within the implementation (that I need to write) I need to call some other functions from a different library (so I can't change them) to which I need to pass *address, but their method signature omit the const keyword:
void some_api_function (char *address, [...]);
Now, if I simply pass *address down to some_api_function, I will get the compiler warning:
warning: passing argument 1 of ‘some_api_function’ discards ‘const’ qualifier from pointer target type [enabled by default]
I tried explicitly casting to char * in the function call like this:
`some_api_function ((char*) address, [...]) { ... }
but then I just get another warning:
warning: cast discards ‘__attribute__((const))’ qualifier from pointer target type [-Wcast-qual]
The problem is, that this is a larger C project with many people working on and policy is that -Werror is enabled and no code emitting warnings on compile is accepted into the mainline source code.
I can't change the interface definition because it is from a third party, and I can't change the API definitions of the external libraries, either. I know that *address is not modified in the external library (it could be const, but as I said I can't change that)
I also know that to solve this issue, I could just create a copy of the const char* into char *, but that doesn't feel right to me because it involves a unnecessary copy operation .
So what is the elegant or 'right' way to do this?
For absolute safety I'd deep copy the string and profile the performance impact. The author of the function makes no guarantee that they will not modify the string. If a parameter is marked const char* there is an implication that the string will not be changed by the function.
There are other choices; casting via (void*) or a clever union trick (see Gung Foo's answer), but neither will guarantee program stability.
You could use a union.
union charunion {
char *chr;
const char* cchr;
} chrptrs;
chrptrs.cchr; // const char *
chrptrs.chr; // char *
Warnings are there for a reason. As Bathseheeba says, the declaration makes no guarantee that the function will not modify the value, so if you know what you are doing -i.e. you know the function will not try to modify the value pointed by 'address'-, you can remove the warning by doing this:
void interface_function (const char *address, [...])
{
char *chrptr=(char *)address;
[...]
some_api_function (chrptr, [...]);
[...]
}
EDIT: I was answering before you commented that you were going with Bathsheeba's suggestion. Good choice.
I was recently making some adjustments to code wherein I had to change a formal parameter in a function. Originally, the parameter was similar to the following (note, the structure was typedef'd earlier):
static MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
The change was made because I could define and initialize my_special_structure before compile time and myFunction never changed the value of it. This led to the following change:
static const MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (const MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
I also noticed that when I ran Lint on my program that there were several Info 818's referencing a number of different functions. The info stated that "Pointer parameter 'x' (line 253) could be declared as pointing to const".
Now, I have two questions in regards to the above. First, in regards to the above code, since neither the pointer nor the variables within MySpecialStructure is changed within the function, is it beneficial to declare the pointer as constant as well? e.g. -
int myFunction (const MySpecialStructure * const p_structure, unsigned char useful_char)
My second question is in regards to the Lint information. Are there any benefits or drawbacks to declaring pointers as a constant formal parameter if the function is not changing its value... even if what you are passing to the function is never declared as a constant? e.g. -
static unsigned char my_char;
static unsigned char * p_my_char;
p_my_char = &my_char;
int myFunction (const unsigned char * p_char)
{
...
}
Thanks for your help!
Edited for clarification -
What are the advantages of declaring a pointer to const or a const pointer to const- as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
What are the advantages of declaring a pointer as a const - as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
I assumed you meant a pointer to const.
By have a pointer to const as a parameter, the advantage is you document the API by telling the programmer your function does not modify the object pointed by the pointer.
For example look at memcpy prototype:
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
It tells the programmer the object pointed to by s2 will not be modified through memcpy call.
It also provides compiler enforced documentation as the implementation will issue a diagnostic if you modify a pointee from a pointer to const.
const also allows to indicate users of your function that you won't modify this parameter behind their back
If you declare a formal parameter as const, the compiler can check that your code does not attempt to modify that parameter, yielding better software quality.
Const correctness is a wonderful thing. For one, it lets the compiler help keep you from making mistakes. An obvious simple case is assigning when you meant to compare. In that instance, if the pointer is const, the compiler will give you an error. Google 'const correctness' and you'll find many resources on the benefits of it.
For your first question, if you are damn sure of not modifying either the pointer or the variable it points to, you can by all means go ahead and make both of them constant!
Now, for your Qn as to why declare a formal pointer parameter as const even though the passed pointer is not constant, A typical use case is library function printf(). printf is supposed to accept const char * but the compiler doesn't complain even if you pass a char* to it. In such a case, it makes sense that printf() doesn't not build upon the user's mistake and alter user's data inadvertantly! Its like printf() clearly telling- Whether you pass a const char * or char*, dont worry, I still wont modify your data!
For your second question, const pointers find excellent application in the embedded world where we generally write to a memory address directly. Here is the detailed explanation
Well, what are the advantages of declaring anything as a const while you have the option to not to do so? After all, if you don't touch it, it doesn't matter if it's const or not. This provides some safety checks that the compiler can do for you, and it gives some information of the function interface. For example, you can safely pass a string literal to a function that expects a const char *, but you need to be careful if the parameter is declared as just a char *.
In my library I have to return a string to the callers. The string I am returning will be a global array, the intended use from the caller is just to read the string. I don't want them to modify it..
Is this the right way to declare the function..
const char * get_some_details();
This should generate a warning (tried only gcc) either when the caller assigns the return value to a char * ptr or assigns to const char * ptr, but later tries to modify it.
I am asking because I would expect functions like getenv() to return const char *. But it returns char *. Is there any gotcha in returning const char * ?
Returning const char* is exactly the right thing to do in these circumstances.
Many older APIs don't use const since they pre-date the introduction of const in C90 (there was no const before then).
That is the right way to do it.
Many standard library functions take or return char * when logically it should be const char *, for historical reasons: pre-C89, there was no const; post-C89, their type signatures could not be changed without breaking application code. As a general rule, do not use the standard library as a style guide; it is very old and contains many things that are no longer considered good practice. (cough gets)