Mảng liên tiếp
Tôi tò mò về một câu trong tiêu chuẩn C18:
Hai con trỏ so sánh bằng nhau nếu và chỉ khi cả hai đều là con trỏ rỗng, cả hai đều là con trỏ đến cùng một đối tượng (bao gồm một con trỏ tới một đối tượng và một subobject ở đầu của nó) hoặc hàm, cả hai đều là con trỏ đến một phần tử cuối cùng của cùng một mảng hoặc một đối tượng là con trỏ tới một đối tượng ở phía trước của một đối tượng mảng và đối tượng kia là con trỏ tới đầu của một đối tượng mảng khác sẽ xảy ra ngay theo sau đối tượng mảng đầu tiên trong không gian địa chỉ. § 6.5,9 6
Tại sao đối tượng theo sau mảng nhất thiết phải là một mảng khác? Không thể chỉ đơn giản là một đối tượng cùng kiểu với kiểu cơ sở mảng (như intngay sau một dấu an int[])?
Không có gì ngạc nhiên khi tôi đã thử mã này:
#include <stdio.h>
struct test { int arr[10]; int i; };
int main() {
struct test t;
int *p, *q;
p = t.arr + 10;
q = &t.i;
if (p == q)
printf("Equal pointers.");
return 0;
}
Và nó tạo ra các con trỏ bằng nhau. Có phải hành vi này hoàn toàn không được đảm bảo, chỉ là một sự trùng hợp do triển khai xác định?
Trả lời
OP: Tại sao đối tượng theo sau mảng nhất thiết phải là một mảng khác?
Nó không. "... bắt đầu của một mảng khác ..." là một sự đơn giản hóa. Thông số kỹ thuật tiếp theo là:
Đối với mục đích của các toán tử này, một con trỏ tới một đối tượng không phải là một phần tử của mảng hoạt động giống như một con trỏ đến phần tử đầu tiên của một mảng có độ dài bằng một với kiểu của đối tượng là kiểu phần tử của nó. C17dr § 6.5.9 7
OP: Không thể chỉ đơn giản là một đối tượng có kiểu giống với kiểu cơ sở mảng (như
intngay sau một dấu anint[])?
Đúng.
Thứ nhất, chỉ định mảng ở đây không loại trừ / cấm một đối tượng nào. Một đối tượng duy nhất trong bộ nhớ không thể phân biệt được với một mảng có kích thước 1.
( Chỉnh sửa : Đọc câu trả lời này để biết trích dẫn từ tiêu chuẩn nêu rõ điều này khi đề cập đến con trỏ)
Thứ hai, tiêu chuẩn cũng cố gắng làm rõ tuyên bố mà bạn đã trích dẫn, với chú thích sau đây chỉ ra các trường hợp áp dụng quy tắc:
Hai đối tượng có thể nằm kề nhau trong bộ nhớ vì chúng là các phần tử liền kề của một mảng lớn hơn hoặc các thành viên liền kề của một cấu trúc không có phần đệm giữa chúng hoặc do việc triển khai đã chọn đặt chúng như vậy, mặc dù chúng không liên quan.
Đặt tất cả lại với nhau, tiêu chuẩn muốn nói ở đây là nói chung, hai con trỏ của các đối tượng khác nhau không nên so sánh bằng nhau. Tuy nhiên, vì việc trỏ một đối tượng ngoài một đối tượng mảng trong bộ nhớ là hợp pháp, nếu xảy ra một đối tượng (mảng) khác tại vị trí đó, thì con trỏ đó vẫn hợp pháp để so sánh bằng một con trỏ với đối tượng liền kề. Bây giờ, có thể có hoặc không có đối tượng hợp lệ tại vị trí này, do các lựa chọn căn chỉnh và khoảng đệm, nhưng nếu có, có thể chấp nhận được các con trỏ này so sánh bằng nhau.
Trong ví dụ của bạn, nếu tôi thay đổi mảng thành một ký tự, các con trỏ có thể sẽ so sánh không bằng nhau vì trình biên dịch sẽ chọn căn chỉnh int thành 4 byte (trên hầu hết các nền tảng 32 hoặc 64 bit), do đó giới thiệu đệm. Hành vi này vẫn hợp pháp theo tiêu chuẩn.
#include <stdio.h>
struct test { char arr[10]; int i; };
int main() {
struct test t;
int *p, *q;
p = (int*)(t.arr + 10);
q = &t.i;
if(p == q)
printf("Equal pointers.");
else
printf("Unequal pointers.");
return 0;
}