memcpy (0,0,0)을 수행하는 것이 안전을 수행합니까?
나는 C 표준에 익숙하지 않고 참아주세요.
그것이 memcpy(0,0,0)
안전 표준에 의해 보장 보장하고 싶습니다 .
내가 사용할 수있는 유일한 제한은 메모리 영역이 겹치면 동작이 정의되지 않는다는 것입니다.
그러나 여기서 메모리 영역이 겹친다 고 생각할 수 있습니까?
저는 C 표준 (ISO / IEC 9899 : 1999)의 초안 버전이 있고 그 호출에 대해 몇 가지 재미있는 이야기가 있습니다. 우선, 다음과 관련하여 (§7.21.1 / 2)를 참조 memcpy
합니다.
size_t
n으로 선언 된 인수 가 함수의 배열 길이를 지정하는 경우 n은 해당 함수에 대한 호출에서 값 0을 누를 수 있습니다. 이 하위 절의 특정 함수에 대한 설명에서 달리 명시 적으로 언급되지 않는 한, 시내 호출에 대한 포인터 인수는 7.1.4에 설명 된대로 여전히 유효한 값을 가져옵니다 . 다음 호출에서 문자를 찾는 함수는 발생하지 않는 경우 두 문자 시퀀스를 비교하는 함수는 0을 반환하며 문자를 복사하는 함수는 0 개의 문자를 복사합니다.
여기에 참조는 다음을 가리.
함수에 대한 인수에 유효하지 않은 값이있는 경우 (예 : 함수 도메인 외부의 값, 프로그램의 주소 공간 공간 외부의 포인터 , 널 포인터 또는 해당하는 변수가 수정 불가능한 스토리지에 대한 포인터 인수가 가변적 인 함수에서 예상하지 없는 유형 (프로모션 후) 또는 유형 (승격 후) 인 경우 동작이 정의되지 않았습니다 .
따라서 C 사양에 따르면
memcpy(0, 0, 0)
널 포인터는 "모형의 값"으로 포장되기 때문에 정의되지 않은 동작이 발생합니다.
즉, 이렇게하면 실제 구현이 memcpy
중단되면 완전히 놀랍습니다. 제가 생각할 수있는 대부분의 구현은 0 바이트를 복사 할 때 아무 작업도 수행하지 않습니다.
재미를 위해 gcc-4.9의 릴리스 노트는 옵티마이 업그레이드 된 규칙을 사용함을 예를 들어
int copy (int* dest, int* src, size_t nbytes) {
memmove (dest, src, nbytes);
if (src != NULL)
return *src;
return 0;
}
copy(0,0,0)
호출 될 때 필요한 결과를 제공합니다 ( https://gcc.gnu.org/gcc-4.9/porting_to.html 참조 ).
나는 gcc-4.9 동작에 다소 양가 적입니다. 동작은 표준을 준수 할 수있는 memmove (0,0,0)를 호출 할 수있는 표준을 준수하는 것이 좋습니다.
memmove
Git 2.14.x (2017 년 3 분기) 에서이 사용법을 고려할 수도 있습니다.
참조 168635 커밋 (2017 7 월 16 일를) 및 1,773,664을 투입 , f331ab9 커밋 , 5,783,980 커밋 에일 (2017 년 7 월 15 일)
르네 Scharfe을 (rscharfe
) . ( 주니 오씨 합병
gitster
하마노 - 에 32f9025 커밋 2017 11 팔월)
지정된 요소 수를 기반으로 크기를 계산하고 해당 숫자 가 0 일 때 포인터를 지원 하는 도우미 매크로MOVE_ARRAY
를 사용합니다 NULL
.
로 원시 호출을 사용 하면 컴파일러가 이후 검사 를 (과도하게) 최적화 할 수 있습니다 .memmove(3)
NULL
NULL
MOVE_ARRAY
겹칠 수있는 배열 항목 범위를 이동하기위한 안전하고 편리한 도우미를 추가합니다.
요소 크기를 추론하고, 바이트 단위로 크기를 제공하기 위해 자동으로 안심하고 안심하고, 요소 크기를 비교 기본하여 유형 장치 검사를 수행memmove(3)
하고NULL
0 요소가 이동되는 경우 포인터를 지원하는 것과 동일합니다 .
#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
static inline void move_array(void *dst, const void *src, size_t n, size_t size)
{
if (n)
memmove(dst, src, st_mult(size, n));
}
예 :
- memmove(dst, src, (n) * sizeof(*dst));
+ MOVE_ARRAY(dst, src, n);
그것은 사용하는 매크로BUILD_ASSERT_OR_ZERO
(과 표현으로, 빌드 시간에 의존한다고 주장 @cond
해야합니다).
조건이 참이 아니거나 컴파일러에서 평가할 수없는 경우 실패합니다.
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
예 :
#define foo_to_char(foo) \
((char *)(foo) \
+ BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
아니요, memcpy(0,0,0)
안전하지 않습니다. 표준 라이브러리는 해당 호출에서 실패하지 않을 것입니다. 그러나 테스트 환경에서 버퍼 오버런 및 기타 문제를 감지하기 위해 memcpy ()에 추가 코드가있을 수 있습니다. 그리고 memcpy ()의 특수 버전이 NULL 포인터에 어떻게 반응하는지는 정의되지 않았습니다.
참고 URL : https://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0
'ProgramingTip' 카테고리의 다른 글
Jshint.com은 "엄격한 사용"을 요구합니다. (0) | 2020.10.30 |
---|---|
C # : "System.Object"와 "object"의 차이점 (0) | 2020.10.30 |
"값 유형과 'null'의 가능한 비교"는 어떻게해야합니까? (0) | 2020.10.30 |
"서명 된 / 서명되지 않은 불일치"경고 (C4018)를 어떻게 처리합니까? (0) | 2020.10.30 |
공급 업체별 의사 요소 / 클래스를 하나의 규칙 세트로 결합 할 수없는 이유는 무엇입니까? (0) | 2020.10.30 |