One-past-malloc을 가리키는 포인터를 사용하는 것이 잘 정의되어 있습니까?
C에서는 배열의 마지막 요소를 가리키는 포인터를 만들어 포인터 산술에 사용하는 것이 좋습니다.단, 참조를 해제하지 않는 한 다음과 같습니다.
int a[5], *p = a+5, diff = p-a; // Well-defined
단, UB는 다음과 같습니다.
p = a+6;
int b = *(a+5), diff = p-a; // Dereferencing and pointer arithmetic
이제 질문이 있습니다.이것은 동적으로 할당된 메모리에 적용됩니까?포인터하지 않고 .malloc()
공합니니다다
int *a = malloc(5 * sizeof(*a));
assert(a != NULL, "Memory allocation failed");
// Question:
int *p = a+5;
int diff = p-a; // Use in pointer arithmetic?
C11의 초안 n4296에서는 어레이를 1개씩 포인트 하는 것을 명확하게 정의하고 있습니다.「 6 . 5 . 6 Language / Expressions / Addition 연산자 :
§ 8 정수형을 가진 식을 포인터에 추가하거나 포인터에서 빼면 결과에는 포인터 피연산자의 유형이 있습니다. ...또한 식 P가 배열 객체의 마지막 요소를 가리키면 식 P+1은 배열 객체의 마지막 요소를 가리키고 식 Q가 배열 객체의 마지막 요소를 가리키면 식 Q-1은 배열 객체의 마지막 요소를 가리키고 있다.결과가 배열 객체의 마지막 요소를 1개 지나갔을 경우, 평가되는 단항 * 연산자의 피연산자로 사용할 수 없습니다.
메모리의 타입은 서브 절에 사전 정의되어 있지 않기 때문에 할당된 타입을 포함한 모든 타입의 메모리에 적용됩니다.
즉, 그 후는 다음과 같습니다.
int *a = malloc(5 * sizeof(*a));
assert(a != NULL, "Memory allocation failed");
둘다요.
int *p = a+5;
int diff = p-a;
, 규칙이되고 있는 것처럼, 「」는 「」를 참조해당됩니다.diff
shall shall 、 아 、 아 、 shall 、 shall 、 shall 。5
.
One-past-malloc을 가리키는 포인터를 사용하는 것이 잘 정의되어 있습니까?
.p
는 할당된 메모리 중 하나를 가리키고 있으며 참조되지 않습니다.
n1570 - § 6.5.6 (p8) :
객체의 지나갔을 , [...]의 할 수 .
*
평가 대상 연산자.
두 포인터를 빼면 동일한 어레이 개체의 요소를 가리키거나 어레이 개체의 마지막 요소를 가리키는 경우에만 유효합니다. 그렇지 않으면 정의되지 않은 동작이 발생합니다.
(p9) :
두 개의 포인터가 감산되면 둘 다 동일한 배열 객체의 요소를 가리키거나 배열 객체의 마지막 요소 뒤에 있는 요소를 가리킵니다. [...]
위의 인용문은 동적으로 할당된 메모리와 정적으로 할당된 메모리 모두에 적합합니다.
int a[5];
ptrdiff_t diff = &a[5] - &a[0]; // Well-defined
int *d = malloc(5 * sizeof(*d));
assert(d != NULL, "Memory allocation failed");
diff = &d[5] - &d[0]; // Well-defined
Jonathan Leffler가 코멘트에서 지적한 것처럼 이것이 동적으로 할당된 메모리에 유효한 또 다른 이유는 다음과 같습니다.
에 대한 연속 호출에 의해 할당된 스토리지의 순서와 인접성
aligned_alloc
,calloc
,malloc
,그리고.realloc
함수는 지정되지 않았습니다.할당이 성공했을 때 반환되는 포인터는 기본적인 정렬 요건이 있는 모든 유형의 오브젝트에 대한 포인터에 할당될 수 있도록 적절히 정렬된 후 할당된 공간에 있는 이러한 오브젝트 또는 해당 오브젝트의 배열에 액세스하기 위해 사용됩니다(공간이 명시적으로 할당 해제될 때까지).
반환된 포인터malloc
상기의 스니펫은 에 할당되어 있습니다.d
할당된 메모리는 5개의 배열입니다.int
물건들.
예, 동적 및 자동 저장 기간이 있는 변수에도 동일한 규칙이 적용됩니다.그것은 심지어 에도 적용됩니다.malloc
1개의 요소에 대한 요구(이 점에 있어서 스칼라는 1개의 소자 배열과 동일).
포인터 산술은 어레이의 끝을 지나는 것을 포함하여 어레이 내에서만 유효합니다.
비회의에서는, 1개의 고려 사항에 주의하는 것이 중요합니다.초기화와 관련하여int a[5] = {0};
컴파일러는 참조 해제하지 마십시오. a[5]
라는 표현으로int* p = &a[5]
; 이것은 다음과 같이 컴파일해야 합니다.int* p = a + 5;
마찬가지로 동적 스토리지에도 동일한 사항이 적용됩니다.
One-past-malloc을 가리키는 포인터를 사용하는 것이 잘 정의되어 있습니까?
네, 하지만 이것이 제대로 정의되지 않은 코너 케이스가 존재합니다.
void foo(size_t n) {
int *a = malloc(n * sizeof *a);
assert(a != NULL || n == 0, "Memory allocation failed");
int *p = a+n;
intptr_t diff = p-a;
...
}
메모리 관리 기능...요청된 공간의 크기가 0인 경우 동작은 구현 정의됩니다.null 포인터가 반환되거나 반환된 포인터가 객체에 액세스하기 위해 사용되지 않는 것을 제외하고 크기가 0이 아닌 것과 같은 동작입니다.C11dr © 7.22.3 1
foo(0)
-->malloc(0)
반환할 수 있다NULL
또는non-NULL
첫 번째 구현에서는NULL
메모리 할당 에러가 아닙니다.이는 코드가 시도 중임을 의미합니다.int *p = NULL + 0;
와 함께int *p = a+n;
포인터 산술에 대한 보증을 통과하지 못하거나 최소한 그러한 코드에 의문을 제기합니다.
0 사이즈의 할당을 회피하는 것으로, 포터블 코드의 메리트를 얻을 수 있습니다.
void bar(size_t n) {
intptr_t diff;
int *a;
int *p;
if (n > 0) {
a = malloc(n * sizeof *a);
assert(a != NULL, "Memory allocation failed");
p = a+n;
diff = p-a;
} else {
a = p = NULL;
diff = 0;
}
...
}
언급URL : https://stackoverflow.com/questions/47900466/is-it-well-defined-to-use-a-pointer-pointing-to-one-past-malloc
'programing' 카테고리의 다른 글
스토어 내에서 액션에 액세스하거나 디스패치를 하는 방법 (0) | 2022.08.13 |
---|---|
Java 문자열에 있는 두 개 이상의 공백을 단일 공백으로 대체하고 선행 및 후행 공백을 삭제하는 방법 (0) | 2022.08.13 |
제공/주입된 VUE 컴포넌트를 유닛 테스트하는 방법 (0) | 2022.08.11 |
VueJS 커스텀 디렉티브 + import 이벤트 (0) | 2022.08.11 |
Vue에서 대화 상자가 완료될 때까지 선택 양식을 변경하지 않도록 하는 방법 (0) | 2022.08.11 |