데이터 배열을 입력하고 포인터를 사용하여 다른 데이터 배열을 출력하는 함수를 작성하고 싶습니다.
두 경우 나는 결과 무엇인지 궁금 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;
}
위의 질문 외에도 const
원본 코드에서 삭제하면 잘 정의 되어 있습니까?
답변
동작이 잘 정의되어있는 것은 사실이지만 그렇지 않습니다. 있다는 사실이지만 컴파일러가 의미하는 바에 따라 “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
.
답변
이것은 잘 정의되어 있으며 (C ++에서는 더 이상 확실하지 않음) const
한정자가 있거나 .
가장 먼저 찾아야 할 것은 엄격한 앨리어싱 규칙 1 입니다. 만약 src
과 dst
같은 객체에 대한 포인트 :
- C에서는 호환 가능한 유형 이어야합니다 .
char*
과char const*
호환되지 않습니다. - C ++에서는 비슷한 유형 이어야합니다 .
char*
와char const*
유사하다.
const
한정자에 관해서는 dst == src
함수가 어떤 src
점을 효과적으로 수정할 때로 src
자격이 없어야 한다고 주장 할 수 있습니다 const
. 이것은 const
작동 하지 않습니다 . 두 가지 경우를 고려해야합니다.
const
에서처럼 객체가로 정의 된char const data[42];
경우 (직접 또는 간접적으로) 수정하면 정의되지 않은 동작이 발생합니다.const
에서와 같이 객체에 대한 참조 또는 포인터 가 정의되면 객체가 2char const* pdata = data;
로 정의되지 않은 경우 기본 객체를 수정할 수 있습니다 (1 참조). 따라서 다음은 잘 정의되어 있습니다.const
int main()
{
int result = 42;
int const* presult = &result;
*const_cast<int*>(presult) = 0;
return *presult; // 0
}
1) 엄격한 앨리어싱 규칙은 무엇입니까?
2) 가 const_cast
안전?
답변
이는 C에 잘 정의되어 있습니다. 엄격한 별칭 지정 규칙은 char
유형 또는 동일한 유형의 두 포인터에 적용되지 않습니다 .
“최적화”가 무엇을 의미하는지 잘 모르겠습니다 const
. 내 컴파일러 (GCC 8.3.0 x86-64)는 두 경우 모두에 대해 동일한 코드를 생성합니다. 추가하면restrict
포인터에 지정자를 생성 된 코드가 약간 나아지지만 포인터는 동일합니다.
(C11 §6.5 7)
객체는 다음 유형 중 하나를 갖는 lvalue 표현식에 의해서만 저장된 값에 액세스해야합니다.
— 객체
의 유효 유형과 호환되는 유형
— 객체의 유효 유형과 호환되는 유형의 정규화 된 버전 — 오브젝트의 유효 유형에 해당하는 부호있는 유형 또는 부호없는 유형 인 유형 (유효한 오브젝트
유형의 규정 된 버전에 해당하는 부호있는 유형 또는 부호없는 유형 인 유형)
-하나를 포함하는 집합 또는 공용체 유형 재귀 적으로 하위 집합 또는 포함 된 공용체의 멤버를 포함하여 전술 한 유형 중 하나 또는
문자 유형.
이 경우 (없이 restrict
) 항상 121
결과를 얻습니다 .