2013-04-25 47 views
8

Dưới đây là một macro để nhận kích thước mảngC++ ý nghĩa của việc kích thước của một mảng

#define array_size(array) \ 
(sizeof(array)/(sizeof(array[0]) * (sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*))) 

Tôi nghĩ bình thường (sizeof (mảng)/(sizeof (array [0])) là đủ tốt để có được kích thước của mảng.

tôi đoán phần

(sizeof(array[0]) * (sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*)) 

là để tránh toàn bộ điều chia cho zero, bất cứ ai có thể giúp giải thích?

Cảm ơn trước.

Chúc mừng,

+0

Tôi đoán đây là để ngăn chặn tình cờ lạm dụng với phần tử con trỏ đầu tiên bị phân rã. - phụ thuộc, điều này sẽ có giá trị '0' ... –

+0

sizeof không bao giờ có thể trở lại ze ro. – john

+6

"là để tránh toàn bộ điều chia cho số không" Ngược lại, nó là để buộc một chia-by-zero tại thời gian biên dịch khi 'sizeof array == sizeof (void *)' và 'sizeof array [0]> sizeof (void *) '. –

Trả lời

12

Nhân sizeof array[0] trong số chia bằng

(sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*)) 

làm cho số chia không nếu

sizeof array == sizeof(void*) 

sizeof array[0] > sizeof(void*) 

Trong những trường hợp đó, bạn nhận được một phân chia bằng 0 trong quá trình biên dịch, điều này sẽ làm cho trình biên dịch thất bại.

Các kiểm tra này là một nỗ lực để phát hiện đối số là con trỏ (có phải là kết quả của chuyển đổi mảng thành con trỏ hay không), vì không thể biết con trỏ "mảng" lớn như thế nào bằng cách sử dụng thương.

Không thành công nếu các loại con trỏ khác có kích thước khác với void* và không phát hiện con trỏ đến những thứ không lớn hơn void* s. Nó có thể gây hại nhiều hơn lợi ích bằng cách ruồng bỏ tác giả theo một cảm giác an toàn sai lầm.

+0

Và tất nhiên có một mảng con trỏ là hoàn toàn hợp pháp và macro này sẽ thất bại trên nó ... –

1

tôi giả sử phần này là rõ ràng: sizeof(array)/sizeof(array[0])

này phần (sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*)) là một biểu thức logic, vì vậy năng suất đúng hay sai. Khi tính toán toàn bộ biểu thức, do đó nhânvới biểu thức logic, trình biên dịch chuyển đổi biểu thức logic thành 0 hoặc 1. Vì vậy, bạn kết thúc với
sizeof(array)/(sizeof(array[0]) * 1) hoặc
sizeof(array)/(sizeof(array[0]) * 0).

Trường hợp đầu tiên là trường hợp bình thường và mong muốn. Trường hợp thứ hai sẽ cung cấp cho bạn một lỗi trình biên dịch vì chia cho số không. Vì vậy, các mã sẽ không biên dịch nếu bạn gọi ví dụ:

long *p; // assuming a platform with sizeof(long)==sizeof(void*) 
array_size(p); 

Nhưng nó sẽ không bắt lỗi như:

char *p; 
array_size(p); 

Và nó sẽ không biên dịch cho một trường hợp I'ld muốn nó biên dịch cho:

long x[1]; // assuming a platform with sizeof(long)==sizeof(void*) 
array_size(x); 

BTW, nếu bạn đang khai báo hàm này như một macro (và trong C++ I'ld thực sự thích các giải pháp mẫu phong cách), bạn nên thay đổi tất cả array trong macro để (array).

6

Tôi nghĩ bình thường (sizeof (mảng)/(sizeof (array [0])) là đủ tốt để có được kích thước của mảng.

Mặc dù nó không phải là câu hỏi chính của bạn, nhưng Cách chính xác để xác định kích thước mảng trong C++ là sử dụng mẫu:

template<typename T, size_t size> 
constexpr size_t array_size(T(&)[size]){ 
    return size; 
} 
+0

Tiền thưởng bổ sung: thông báo lỗi rõ ràng hơn nhiều khi đối số không phải là một mảng. Nó sẽ là 'constexpr', mặc dù. – MSalters

+0

Có, lý tưởng nó phải là 'constexpr'. Thật không may, nhiều trình biên dịch được sử dụng ngày nay không hỗ trợ nó, do đó tôi đã bỏ qua nó. –

Các vấn đề liên quan