Wil*_*lly 15 c c++ constants undefined-behavior
我想编写一个函数,输入一个数据数组并使用指针输出另一个数据数组。
我想知道如果两者都指向同一个地址会产生什么结果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\n", s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
除了上面的问题,如果我删除const
原来的代码,这个定义是否明确?
ein*_*ica 17
虽然行为是明确定义的,但编译器不能按照您的意思“针对 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;
}
Run Code Online (Sandbox Code Playgroud)
该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
Run Code Online (Sandbox Code Playgroud)
看到这个直播GodBolt。
restrict
只是 C 中的关键字(自 C99 起);不幸的是,到目前为止它还没有被引入到 C++ 中(因为在 C++ 中引入它更复杂)。然而,许多编译器确实有点支持它,因为__restrict
.
底线:编译器在编译时必须支持您的“深奥”用例f()
,并且不会有任何问题。
请参阅这篇文章关于用例restrict
。
这是明确定义的(在 C++ 中,在 C 中不再确定),带和不带const
限定符。
首先要寻找的是严格的别名规则1。如果src
和dst
指向同一个对象:
关于const
限定符,您可能会争辩说,因为当dst == src
您的函数有效地修改src
指向的内容时,src
不应将其限定为const
. 这不是const
工作方式。需要考虑两种情况:
const
,如在 中char const data[42];
,修改它(直接或间接)会导致未定义行为。const
对象的引用或指针被定义时,如在 中char const* pdata = data;
,只要它没有被定义为const
2(见 1.),就可以修改底层对象。所以以下是明确定义的:int main()
{
int result = 42;
int const* presult = &result;
*const_cast<int*>(presult) = 0;
return *presult; // 0
}
Run Code Online (Sandbox Code Playgroud)
1) 什么是严格的别名规则?
2) 是const_cast
安全的吗?