Mỗi C lập trình viên có thể xác định số phần tử trong một mảng với vĩ mô nổi tiếng này:Đáng tin cậy xác định số phần tử trong một mảng
#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
Đây là một trường hợp sử dụng điển hình:
int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19};
printf("%lu\n", NUM_ELEMS(numbers)); // 8, as expected
Tuy nhiên, không có gì ngăn cản các lập trình viên từ vô tình đi qua một con trỏ thay vì một mảng:
int * pointer = numbers;
printf("%lu\n", NUM_ELEMS(pointer));
Trên hệ thống của tôi, điều này in 2, bởi vì rõ ràng, một con trỏ lớn gấp hai lần số nguyên. Tôi đã nghĩ về cách ngăn chặn lập trình viên truyền con trỏ do nhầm lẫn và tôi đã tìm thấy một giải pháp:
#define NUM_ELEMS(a) (assert((void*)&(a) == (void*)(a)), (sizeof(a)/sizeof 0[a]))
Điều này hoạt động vì con trỏ tới mảng có cùng giá trị với con trỏ đến phần tử đầu tiên. Nếu bạn vượt qua một con trỏ thay vào đó, con trỏ sẽ được so sánh với một con trỏ đến chính nó, mà hầu như luôn luôn là sai. (Ngoại lệ duy nhất là một khoảng trống con trỏ đệ quy, tức là một con trỏ void trỏ đến bản thân tôi có thể sống với điều đó..)
Vô tình đi qua một con trỏ thay vì một mảng hiện nay gây ra một lỗi khi chạy:
Assertion `(void*)&(pointer) == (void*)(pointer)' failed.
Tốt! Bây giờ tôi có một vài câu hỏi:
Tôi có sử dụng
assert
làm toán hạng trái của biểu thức dấu phẩy hợp lệ C không? Tức là, tiêu chuẩn cho phép tôi sử dụngassert
như một biểu thức? Xin lỗi nếu đây là câu hỏi ngớ ngẩn :)Kiểm tra bằng cách nào đó có thể được thực hiện tại thời gian biên dịch không?
Trình biên dịch C của tôi cho rằng
int b[NUM_ELEMS(a)];
là VLA. Bất kỳ cách nào để thuyết phục anh ta khác?Tôi có phải là người đầu tiên nghĩ về điều này không? Nếu vậy, có bao nhiêu trinh nữ tôi có thể mong đợi để chờ đợi tôi ở trên thiên đàng? :)
Đối với một phần (4), khá chắc chắn rằng nó * không * 72. Tôi nghĩ rằng t mũ của một giá trị dành riêng cho cái gì khác ... –
Bạn không có nghĩa là 'sizeof a [0]'? –
Mỗi lập trình viên c đều biết rằng việc theo dõi kích thước của mảng là vấn đề của họ, không phải trình biên dịch và các thủ thuật để "tìm ra" là tiện ích giới hạn bởi vì thông tin đó chỉ được giữ lại trong phạm vi.Nếu bạn muốn trình biên dịch xử lý việc này cho bạn, hãy sử dụng một ngôn ngữ thông minh hơn. Tôi có nghĩa là, bạn chỉ cần đi đến c + + và sử dụng 'std :: vector' hoặc (với C++ 11)' std :: array', do đó, nó không phải là một thay đổi lớn. – dmckee