C - Function processing a const * - c

I have a function which search something in a const *. And returns such a const * to the found element. Therefore the function is not changing anything and I actually want to maintain the "const" for readability and reuseability.
But I have another function which calls the function with just a * and then works with the returned value. But in this use-case the value should be changed. But because the returned value is a const * I can not do that.
Would should I adjust in my programming pattern to evade that problem?
const void* search_min_vector_element(const void* vector, size_t length, size_t element_size, int(*cmp_fnc) (const void*, const void*));
This is the first function.
void* min_element = search_min_vector_element((unsigned char*) vector + (i * element_size), length - i, element_size, cmp_fnc);
And that is the call in the second one. vector is void* in this case. And because of that I want to modify it.
Thanks for your help.

You can pick which function to execute based on the type of the argument. Write a _Generic macro to select which types to allow, then call the appropriate function based on that. Example:
#include <stdio.h>
char* print_str (char* str)
{
printf("%s\n", str);
return str;
}
const char* print_str_const (const char* str)
{
printf("const %s\n", str);
return str;
}
#define print(str) \
_Generic((str), \
const char*: print_str_const, \
char*: print_str) (str)
int main(void)
{
const char* cstr = "hello";
char* str = "world";
cstr = print(cstr); // ok
str = print(str); // ok
cstr = print(str); // ok
//str = print(cstr); // compiler error, incorrect assignment
//str = print((void*)str); // compiler error, wrong type
}

In C++ you have a lot of options to deal with this. But since this is C, create another function is the best solution I can currently come up with:
const void* search_min_vector_element_const(const void* vector, size_t length, size_t element_size, int(*cmp_fnc) (const void*, const void*));
void* search_min_vector_element ( void* vector, size_t length, size_t element_size, int(*cmp_fnc) ( void*, void*));
You can also force-cast the result directly:
void* min_element = (void*)search_min_vector_element((unsigned char*) vector + (i * element_size), length - i, element_size, cmp_fnc);

I would really recommend to change the return type (if you can) to not be a constant value. It is really not the search_min_vector_element's business what another function shall do with the result.
If you cannot change the return type, then you will need to:
const void* value = search_min_vector_element(....)
void* second_no_const_value = *value; // copy value of the value pointed by constant pointer.

Since you know for a fact that you hold a non-const pointer to vector, you should simply cast the const pointer you receive:
void* min_element = (void*)search_min_vector_element(...);

Technically you may cast from const char* to char* through an explicit cast without yielding undefined behaviour per se; But if you alter a value that must not be altered (e.g. a string literal), you get undefined behaviour then. So the const-qualifier will not prohibit a change of the underlying data, but when used as qualifier in a function argument or return value, the function prototype pretends that the value is not meant to be altered.
Hence, if you - or a library - provides a function with return type const char*, without knowing the implementation, one shall not assume that the returned value points to memory that may be altered. See the following example illustrating this. Functions validImpl1 and validImpl2 have - apart from the name - the same signature but different implementations. Provided that you pass in a parameter which's content may be altered, casting the return value to char* for the first is OK, but for the second one it yields UB. So unless you know the internals of the function, you should never cast from const char* to char *:
const char* validImpl1(const char* t) {
return t;
}
const char* validImpl2(const char* t) {
return "Hello!";
}
int main() {
char x[100] = "Herbert";
char* t=(char*) validImpl1(x);
*t = 'a'; // OK
printf("%s\n",t);
char* t2=(char*) validImpl2(x);
*t2 = 'a'; // Undefined behaviour here.
printf("%s\n",t2);
}
In your case, if you are the one offering the function and knowing about the implementation details, you could offer two functions, one with const char* and one with char*, where the latter simply calls the former. So the ones who use your functions can rely on that what the function prototypes pretend.

Related

Assigning a pointer to the const function arguement pointer

Say I have a const pointer to an array as a function argument like so:
int* test(const int* inputArg)
And within the function I want to assign inputArg as one of the members of a struct, like so:
typedef struct {
int * intArray;
} structSample;
structSample abc;
abc.intArray = inputArg;
How should I cast inputArg to achieve this? Right now if I compile it, error will be shown saying that
error: assigning to 'int *' from 'const int *'
Thank you
First of all, you do not have
a const pointer to an array
What you have is a pointer to constant integer. If you really wanted a constant pointer to integer as an argument, you would have to have the prototype declared as follows:
int* test(int* const inputArg)
Unless, of course, something else was in mind.
Update from comment:
So basically if you want to have a pointer to constant int stored in your function as a struct member, you can declare it just like that:
struct SampleStruct
{
const int* a;
/* whatever follows */
};
int* test(const int* inputArg)
{
struct SampleStruct ss;
ss.a = inputArg;
/* other code */
}
You must be aware, that in doing so, you must be const correct. That means, since both (argument and field) are pointers to constant integers, you must not change the values at that address(es).
abc.intArray = (int*)inputArg;
This is the C-style cast. On a side not the compiler didn't allow the const conversion by default because it's dangerous to do so. You are removing the const at your own risk.
For eg if your test is called like
const int max = 100;
//centuries later
test(&max);
and you do go ahead with the cast:
abc.intArray = (int*)inputArg;
// after another century later
*(abc.intArray) = 10; // kaboom. Undefined behavior. Debugging is a nightmare at this point
The best solution here would be changing the function to
int* test(int* inputArg)
{
/* do whatever you wish to do with inputArg itself
* why bother to create a structure and all?
* The whole purpose you wanted the const int* inputArg
* was to prevent any accidental change of data pointed to by it
* Wasn't it?
*/
}
It looks like that you are using Werror flag (this shouldn't be an error but a warning)
There is a way to lie to the compiler (using unions) without warnings:
#include <stdio.h>
int *test(const int *inputArg)
{
union {int *nonconstant; const int *constant;} fake = {.constant = inputArg};
int *p = fake.nonconstant;
return p;
}
int main(void)
{
const int x = 500;
int *p = test(&x);
*p = 100; /* Boom */
return 0;
}
As pointed out by others, don't do it :)

C: Illegal conversion between pointer types: pointer to const unsigned char -> pointer to unsigned char

The following code is producing a warning:
const char * mystr = "\r\nHello";
void send_str(char * str);
void main(void){
send_str(mystr);
}
void send_str(char * str){
// send it
}
The error is:
Warning [359] C:\main.c; 5.15 illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
How can I change the code to compile without warnings? The send_str() function also needs to be able to accept non-const strings.
(I am compiling for the PIC16F77 with the Hi-Tech-C compiler)
Thanks
You need to add a cast, since you're passing constant data to a function that says "I might change this":
send_str((char *) mystr); /* cast away the const */
Of course, if the function does decide to change the data that is in reality supposed to be constant (such as a string literal), you will get undefined behavior.
Perhaps I mis-understood you, though. If send_str() never needs to change its input, but might get called with data that is non-constant in the caller's context, then you should just make the argument const since that just say "I won't change this":
void send_str(const char *str);
This can safely be called with both constant and non-constant data:
char modifiable[32] = "hello";
const char *constant = "world";
send_str(modifiable); /* no warning */
send_str(constant); /* no warning */
change the following lines
void send_str(char * str){
// send it
}
TO
void send_str(const char * str){
// send it
}
your compiler is saying that the const char pointer your sending is being converted to char pointer. changing its value in the function send_str may lead to undefined behaviour.(Most of the cases calling and called function wont be written by the same person , someone else may use your code and call it looking at the prototype which is not right.)

idiomatic C for const double-pointers

I am aware that in C you can't implicitly convert, for instance, char** to const char** (c.f. C-Faq, SO question 1, SO Question 2).
On the other hand, if I see a function declared like so:
void foo(char** ppData);
I must assume the function may change the data passed in.
Therefore, if I am writing a function that will not change the data, it is better, in my opinion, to declare:
void foo(const char** ppData);
or even:
void foo(const char * const * ppData);
But that puts the users of the function in an awkward position.
They might have:
int main(int argc, char** argv)
{
foo(argv); // Oh no, compiler error (or warning)
...
}
And in order to cleanly call my function, they would need to insert a cast.
I come from a mostly C++ background, where this is less of an issue due to C++'s more in-depth const rules.
What is the idiomatic solution in C?
Declare foo as taking a char**, and just document the fact that it won't change its inputs? That seems a bit gross, esp. since it punishes users who might have a const char** that they want to pass it (now they have to cast away const-ness)
Force users to cast their input, adding const-ness.
Something else?
Although you already have accepted an answer, I'd like to go for 3) namely macros. You can write these in a way that the user of your function will just write a call foo(x); where x can be const-qualified or not. The idea would to have one macro CASTIT that does the cast and checks if the argument is of a valid type, and another that is the user interface:
void totoFunc(char const*const* x);
#define CASTIT(T, X) ( \
(void)sizeof((T const*){ (X)[0] }), \
(T const*const*)(X) \
)
#define toto(X) totoFunc(CASTIT(char, X))
int main(void) {
char * * a0 = 0;
char const* * b0 = 0;
char *const* c0 = 0;
char const*const* d0 = 0;
int * * a1 = 0;
int const* * b1 = 0;
int *const* c1 = 0;
int const*const* d1 = 0;
toto(a0);
toto(b0);
toto(c0);
toto(d0);
toto(a1); // warning: initialization from incompatible pointer type
toto(b1); // warning: initialization from incompatible pointer type
toto(c1); // warning: initialization from incompatible pointer type
toto(d1); // warning: initialization from incompatible pointer type
}
The CASTIT macro looks a bit complicated, but all it does is to first check if X[0] is assignment compatible with char const*. It uses a compound literal for that. This then is hidden inside a sizeof to ensure that actually the compound literal is never created and also that X is not evaluated by that test.
Then follows a plain cast, but which by itself would be too dangerous.
As you can see by the examples in the main this exactly detects the erroneous cases.
A lot of that stuff is possible with macros. I recently cooked up a complicated example with const-qualified arrays.
2 is better than 1. 1 is pretty common though, since huge volumes of C code don't use const at all. So if you're writing new code for a new system, use 2. If you're writing maintenance code for an existing system where const is a rarity, use 1.
Go with option 2. Option 1 has the disadvantage that you mentioned and is less type-safe.
If I saw a function that takes a char ** argument and I've got a char *const * or similar, I'd make a copy and pass that, just in case.
Modern (C11+) way using _Generic to preserve type-safety and function pointers:
// joins an array of words into a new string;
// mutates neither *words nor **words
char *join_words (const char *const words[])
{
// ...
}
#define join_words(words) join_words(_Generic((words),\
char ** : (const char *const *)(words),\
char *const * : (const char *const *)(words),\
default : (words)\
))
// usage :
int main (void)
{
const char *const words_1[] = {"foo", "bar", NULL};
char *const words_2[] = {"foo", "bar", NULL};
const char *words_3[] = {"foo", "bar", NULL};
char *words_4[] = {"foo", "bar", NULL};
// none of the calls generate warnings:
join_words(words_1);
join_words(words_2);
join_words(words_3);
join_words(words_4);
// type-checking is preserved:
const int *const numbers[] = { (int[]){1, 2}, (int[]){3, 4}, NULL };
join_words(numbers);
// warning: incompatible pointer types passing
// 'const int *const [2]' to parameter of type 'const char *const *'
// since the macro is defined after the function's declaration and has the same name,
// we can also get a pointer to the function
char *(*funcptr) (const char *const *) = join_words;
}

Change string pointed by pointer

Many functions in c take pointer to constant strings/chars as parameters eg void foo(const char *ptr) . However I wish to change the string pointed by it (ptr).how to do it in c
You can just cast away the const:
void evil_function(const char *ptr)
{
char *modifiable = (char *) ptr;
*modifiable = 'f';
}
Note that this is dangerous, consider cases where the data being passed to the function really can't be changed. For instance, evil_function("bar"); might crash since the string literal is often placed in read-only memory.
Don't do it as it will cause your code to behave unpredictably. Basically the string pointed by const char* may be stored in the read-only section of your program's data and if you try to write something there, bad things will happen. Remember that foo can be called as foo("Test"), here you have not allocated memory for "Test" yourself, you just have a pointer to memory which contains the string. This memory may be read-only.
You can copy it to another piece of memory, and modify it there.
If you cast it to non-const, and then modify, chances are good you'll just segfault.
void foo(const char *x);
char data[4] = "Hi!";
int sum = 0;
for (int k=0; k<strlen(data); k++) {
foo(data); /* foo first */
sum += data[k];
}
printf("%d\n", sum);
Because foo() does not change its argument, the compiler can change this code to
void foo(const char *x);
char data[4] = "Hi!";
int sum = 0;
for (int k=0; k<strlen(data); k++) {
sum += data[k]; /* sum first */
foo(data);
}
printf("%d\n", sum);
But, if foo() changes the values in the data array, the results will be different according to the order the compiler chose to code the loop!
In short: don't lie to your compiler
How to lie to the compiler
Cast the const away
void foo(const char *readonly) {
char *writable = (char *)readonly;
/* now lie to the compiler all you like */
}
by notation "const char *ptr" we are telling Compiler
that ptr contains should not be changed.
Just, we can't change it!
The whole reason the const is so to express that the underlying content is not to be modified by this function, so don't change it because that will most likely break some code which is relying on the constness. other then that you can always cast the constness away using either const_cast<char*> or by directly casting the pointer
If you do it like this:
void dont_do_this_at_home(const char *ptr)
{
char **steve-o_ptr = (char **) &ptr;
char *bam_margera = "viva la bam";
*steve-o_ptr = bam_margera;
}
Then the pointer that you send into the function will be changed despite being a const pointer, the other suggestions so far only let you change the contents of the string, not the pointer to the string.
And I agree with the others that you shouldn't, ever, "un-const" any parameter you get, since the callee may really depend on that there are no side-effects to the function regarding those parameters.
There is also this way to get rid of the warnings/errors
typedef struct {
union {
const void* the_const;
void* the_no_const;
} unconsting;
}unconst_t;
/* Here be dragons */
void* unconst_pointer(const void* ptr) {
unconst_t unconst.unconsting.the_const = ptr;
return unconst.unconsting.the_no_const;
}
As you see it is quite possible and popular to actually do this, but you have to know what you are doing or mysterious faults may appear.

Returning a void pointer to a constant object in C

I'm writing an access function which returns a pointer to an internal buffer and I'd like to hint to users of my function that they shouldn't update the object that's pointed to. A very contrived example would be:
void myAccessFunc(bool string, void* p, size_t* len)
{
static const char* s = "aha!";
static const int i = 123;
if (string) {
*(char**)p = &s;
*len = strlen(s);
}
else {
*(int**)p = &i;
*len = sizeof(i);
}
}
char* s;
size_t bytes;
myAccessFunc(true,&s, &bytes);
printf("Got '%s'\n", s);
Yes, I know that looks flakey.
What I want to prevent is:
char* s;
size_t bytes;
myAccessFunc(true,&s,&bytes);
s[4] = '?';
I know I can't completely prevent it but I'd at least like the compiler warning to hint to a user that they shouldn't be doing that. If they cast my pointer, then that's their problem. Is there some combination of const and void and * that will do this? I tried something like:
void myAccessFunc(bool string, const void** p, size_t* len);
but it seemed do away with the voidness of the pointer so a caller had to do:
const void* p;
size_t bytes;
myAccessFunc(true, &p, &bytes);
or
const char* s;
size_t bytes;
myAccessFunc(true, (const void**)&s, &bytes);
and couldn't do:
const int * ip;
const char* s;
size_t bytes;
myAccessFunc(true, &s, &bytes);
myAccessFunc(false, &i, &bytes);
I finally came around to:
const void* myAccessFunc(bool string, size_t* len);
and if the user does:
char* p = myAcccessFunc(true,&bytes);
the compiler (GCC, at least), does complain about throwing away the qualifier.
It would be best to do something like:
const void * myAccessFunc();
Where you return the pointer to the internals, this is a bit more natural than passing it as an out parameter.
If you were to pass it as an out parameter, you would want:
void myAccessFunc(const void **p);
which prevents them from doing this accidentally:
void *p; /* error: must be 'const void *p;' */
myAccessFunc(&p);
You have two things you can do:
Return a const void*
Write some documentation for your API telling the users not to modify the returned value
With that said, any API user who decides to try and muck with a pointer like that deserves what they get :P.
Preventing is impossible, since you can cast away constness. If you make your function parameter const, you'll have to cast it away yourself inside the function. You'd also be lying to anyone using your function and could cause all sorts of fun bugs.
You could try returning a pointer instead. Then you'd at least not be violating your own const. That may not be appropriate in this case though.
Returning a pointer would be best, but if you absolutely need to make it an out parameter, you could use a struct as an intermediary:
typedef struct _ptr_holder {
const void* ptr;
} ptr_holder;
void myAccessFunc( bool string, ptr_holder* ptr ) {
...
}
ptr_holder s;
myAccessFunc(true,&s);
printf("Got '%s'\n", s.ptr);
It's hokey, but it should do the trick
So you want to prevent modification of via the pointer you return? Try this:
const void* myAccessFunc(bool string);
What is wrong with this? If you are going to vote down a valid answer, please leave a comment.
If you are writing a C library where you don't want to expose some internal data-structure it can be good to go an extra route and hide implementation with a unspecified struct typedef. This is also called an opaque types
Example:
In my_interface.h
#ifndef __MYINTERFACE_H__
#define __MYINTERFACE_H__
/* The unspecified struct statement */
typedef struct s_my_data t_my_data;
t_my_data *new_my_data(int someInitializer);
void free_my_data(t_my_data *data);
int enter_my_data(t_my_data *data, int someDataToEnter);
const char *return_str_my_data(t_my_data *data);
#endif /* __MYINTERFACE_H__ */
In my_interface.c
#include <my_interface.h>
/* Keep struct in .c file */
struct s_my_data {
int length;
char *string;
};
t_my_data *new_my_data(int someInitializer)
{
/* the exercise */
}
void free_my_data(t_my_data *data)
{
/* the exercise */
}
int enter_my_data(t_my_data *data, int someDataToEnter)
{
/* the exercise */
}
const char *return_str_my_data(t_my_data *data)
{
/* the exercise */
}
Is this C or C++?
Why in the int case are you passing the pointer to a static const?
The interface is suspect.
Overload and get rid of the boolean in the interface:
void myAccessFunc( const char* * const p, size_t* len){
*p = "blahblahblah";
*len = 12;
}
void myAccessFunc( const int* * const ppI, size_t* len){
static const int i = 123;
*ppI = &i;
*len = 4;
}
Gets rid of the test too. Since the user knows true or false for the original function he knows which one to use. Strong typing is your friend. Gets rid of the class of errors where type and pointer are inconsistent...
BTW passing such control flags versus overloading is undesirable, especially so in small methods.

Resources