使用指向非常数的指针和指向相同地址的常量参数的指针的函数调用
我要编写一个函数,该函数使用指针输入一个数据数组并输出另一个数据数组。
我想知道,如果src
和dst
都指向同一个地址,结果会是什么,因为我知道编译器可以针对const进行优化。它是不是未定义的行为?(我标记了C和C++,因为我不确定它们之间的答案是否会不同,我想知道两者的情况。)
void f(const char *src, char *dst) {
dst[2] = src[0];
dst[1] = src[1];
dst[0] = src[2];
}
int main() {
char s[] = "123";
f(s,s);
printf("%s
", s);
return 0;
}
除了上面的问题,如果我删除原始代码中的const
,这个定义是否明确?
解决方案
虽然行为确实定义良好-但编译器可以在您所指的意义上针对常量进行优化,这并不是。
也就是说,不允许假设只因为一个参数是const T* ptr
,ptr
指向的内存不会通过另一个指针更改。指针甚至不一定要相等。const
是一种义务,而不是保证-您(=函数)不通过指针进行更改义务。
restrict
关键字标记指针。因此,如果您编译这两个函数:
int foo(const int* x, int* y) {
int result = *x;
(*y)++;
return result + *x;
}
int bar(const int* x, int* restrict y) {
int result = *x;
(*y)++;
return result + *x;
}
foo()
函数必须从x
读取两次,而bar()
只需读取一次:
foo:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, DWORD PTR [rdi] # second read
ret
bar:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, eax # no second read
ret
观看直播GodBolt。
restrict
只是C中的一个关键字(从C99开始);不幸的是,到目前为止它还没有被引入到C++中(因为在C++中引入它更复杂)。然而,许多编译器确实有点支持它,例如__restrict
。
底线:编译器在编译f()
时必须支持您的深奥用例,并且不会有任何问题。
有关
restrict
的用例,请参阅this post。
相关文章