void f1(int* count, char* str) {
for (int i = 0; i < *count; ++i) str[i] = 0;
}
void f2(int* count, char8_t* str) {
for (int i = 0; i < *count; ++i) str[i] = 0;
}
void f3(int* count, char* str) {
int n = *count;
for (int i = 0; i < n; ++i) str[i] = 0;
}
void f4(int* __restrict__ count, char* str) { // GCC extension; clang also supports it
for (int i = 0; i < *count; ++i) str[i] = 0;
}
According to this article,
the compiler (almost) replaces f2() with a call to memset(),
however, the compiler generates machine code from f1() that is almost identical to the above code.
Because the compiler can assume that count and str do not point to the same int object (strict aliasing rule) in f2(),
but cannot make such an assumption in f1() (C++ allow aliasing any pointer type with a char*).
Such aliasing problems can be avoided by dereferencing count in advance, as in f3(), or by using __restrict__, as in f4().
https://godbolt.org/z/fKTjcnW5f
The following functions are std::string/std::u8string version of the above functions:
void f5(int* count, std::string& str) {
for (int i = 0; i < *count; ++i) str[i] = 0;
}
void f6(int* count, std::u8string& str) {
for (int i = 0; i < *count; ++i) str[i] = 0;
}
void f7(int* count, std::string& str) {
int n = *count;
for (int i = 0; i < n; ++i) str[i] = 0;
}
void f8(int* __restrict__ count, std::string& str) {
for (int i = 0; i < *count; ++i) str[i] = 0;
}
void f9(int* __restrict__ count, std::string& __restrict__ str) {
for (int i = 0; i < *count; ++i) str[i] = 0;
}
https://godbolt.org/z/nsPdfhzoj
My questions are:
f5()andf6()are the same result asf1()andf2(), respectively. However,f7()andf8()do not have the same result asf3()andf4()(memset()was not used). Why?- The compiler replaces
f9()with a call tomemset()(that does not happen withf8()). Why?
Tested with GCC 12.1 on x86_64, -std=c++20 -O3.