I am attempting some optimization of code, but it is hard to wrap my head around whether "restrict" is useful in this situation or if it will cause problems.
I have a function that is passed two strings (char*) as well as an int (int*).
The second string is copied into memory following the first string, at the position indicated by the int. If this would overrun the allocation of memory for the first string, it must reallocate memory for the first string before doing so. A new pointer is created with the new allocation, and then the original first string pointer is set equal to it.
char* concatFunc (char* restrict first_string, char* const restrict second_string, int* const restrict offset) {
size_t block = 200000;
size_t len = strlen(second_string);
char* result = first_string;
if(*offset+len+1>block){
result = realloc(result,2*block);
}
memcpy(result+*offset,second_string,len+1);
*offset+=len;
return result;
}
The above function is repeatedly called by other functions that are also using the restrict keyword.
char* addStatement(char* restrict string_being_built, ..., int* const restrict offset){
char new_statement[30] = "example additional text";
string_being_built = concatFunc(string_being_built,&new_statement,offset);
}
So in the concatFunc the first_string is restricted (meaning memory pointed to will not be changed from anywhere else). But then if I am reallocating a pointer that is a copy of that, is that going to cause undefined behavior or is the compiler smart enough to accommodate that?
Basically: What happens when you restrict a pointer parameter, but then change the pointer.
What happens when you restrict a pointer parameter, but then change the pointer.
It depends on how the pointer was changed - and in this case, memcpy()
risks UB.
With char* result = first_string;
, inherits the restrict
of char* restrict first_string
.
After result = realloc(result,2*block);
, result
is as before and accessing via result
does not collide with accessing through second_string
or offset
or result
is new memory and accessing via result
does not collide with accessing through second_string
or offset
.
Yet can the compiler know the newly assigned result
has those one of two above properties of realloc()
? After all, realloc()
might be a user defined function and compiler should not assume result
now has the restrict
property anymore.
Thus memcpy()
is in peril.
is the compiler smart enough to accommodate that?
I do not see it can, other than warn about memcpy()
usage.
Of course OP can use memmove()
instead of memcpy()
to avoid the concern.
As I see it, a simplified example would be:
char* concatFunc (char* restrict first_string, char* restrict second_string) {
int block = rand();
first_string = foo(first_string, block);
// first_string at this point may equal second_string,
// breaking the memcpy() contract
memcpy(first_string, second_string, block);
return first_string;
}
Or even simpler
char* concatFunc (char* /* no restrict */ first_string, char* restrict second_string) {
return memcpy(first_string, second_string, 2);
}