2010-12-11 39 views
27

Tôi đã nhìn thấy một vài macro cho chiều dài mảng nổi xung quanh:Macro chiều dài mảng chung cho C?

Từ this question:

  • #define length(array) (sizeof(array)/sizeof(*(array)))
  • #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
  • #define SIZE(array, type) (sizeof(array)/(sizeof(type))

Và Visual Studio của _countof:

#define _countof(_Array) (sizeof(_Array)/sizeof(_Array[0])) 

Những gì tôi muốn biết là:

  1. sự khác biệt giữa những người sử dụng array[0]*array là gì?
  2. Tại sao nên được ưu tiên?
  3. Chúng khác nhau trong C++?

Trả lời

51

Dưới đây là một phiên bản C tốt hơn (từ dự án Chromium của Google):

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x]))/((size_t)(!(sizeof(x) % sizeof(0[x]))))) 

Nó cải thiện trên phiên bản array[0] hay *array bằng cách sử dụng 0[array], tương đương với array[0] trên mảng đơn giản, nhưng sẽ thất bại trong việc biên dịch nếu array xảy ra là loại C++ quá tải operator[]().

Phân chia gây ra hoạt động chia theo số không (phải được tính tại thời gian biên dịch vì đây là biểu thức hằng số biên dịch) cho nhiều trường hợp (nhưng không phải tất cả) trong đó con trỏ được chuyển thành tham số array.

Xem Is there a standard function in C that would return the length of an array? để biết thêm chi tiết.

Có một tùy chọn tốt hơn cho mã C++. Xem Compile time sizeof_array without using a macro để biết chi tiết.

+8

Điều đó cực kỳ khó hiểu chỉ để bảo vệ chống lại việc sử dụng sai trong C++, xem xét rằng cái gì khác nên được sử dụng trong C++ anyway. –

+1

Bạn nói đúng rằng điều này không nên được sử dụng trong C++, nhưng bit cung cấp một số sự an toàn đặc biệt cho C++ không thực sự quá khó hiểu (nó chỉ là việc lập chỉ mục bất thường). Các phần bảo vệ thực sự khó hiểu chống lại một số loại lạm dụng trong C mà thực sự là khá khó khăn để bảo vệ chống lại (và vĩ mô thậm chí không hoàn hảo bảo vệ chống lại lạm dụng này). Việc lạm dụng nó bảo vệ chống lại (đi qua một con trỏ thay vì một đối số mảng) xảy ra thường xuyên mà nó trả tiền để có sự phức tạp. Được bao bọc trong một macro, sự phức tạp không phải là quá nhiều của một vấn đề (và macro này ít khó hiểu hơn nhiều so với tôi gặp phải). –

+0

Loại địa ngục nào là '0 [x]'? Bạn có thể làm điều đó? –

3

1) Không có gì, giá trị của mảng là con trỏ đến phần tử đầu tiên. Vì vậy * mảng == array [0]
2) Cá nhân Preference
3) Không

Lưu ý rằng công việc sẽ không macro này nếu gọi là bên trong một hàm nơi mảng được truyền như một tham số vào hàm. Điều này là do đối tượng mảng truyền qua "phân rã" thành một con trỏ chứ không phải là một bản sao sâu.

+0

Có, nó có thể hoạt động hiệu quả như 'sizeof (void *)/sizeof (mảng [0])', trong thực tế đương đại - có nghĩa là 8, 4, 2, 1 hoặc 0.;) Dù sao - không có gì có thể giúp bạn trong một chức năng như vậy tại thời gian biên dịch - bạn không bao giờ có thể biết ai gọi nó, và với một mảng lớn như thế nào. –

15
  1. Sự khác nhau giữa những mảng sử dụng mảng [0] và * là gì?
  2. Tại sao nên được ưu tiên?
  3. Chúng khác nhau trong C++?

(1) Không có sự khác biệt trong C. Không có sự khác biệt cho một mảng thực tế trong C++.

(2) Không có cơ sở kỹ thuật để thích cái này hay cái kia, nhưng người mới có thể bị nhầm lẫn bởi sự dereference của con trỏ.

(3) Trong C++, bạn thường không sử dụng macro vì nó rất không an toàn. Nếu bạn vượt qua trong một con trỏ thay vì một mảng thô thực tế, mã sẽ biên dịch nhưng mang lại kết quả không chính xác. Vì vậy, trong C++ bạn nên/thay vào đó nên sử dụng một mẫu chức năng, như & hellip;

#include <stddef.h> 

typedef ptrdiff_t Size; 

template< class Type, Size n > 
Size countOf(Type (&)[n]) { return n; } 

Chỉ chấp nhận mảng thô thực tế làm đối số.

Đó là một phần của bộ ba chức năng startOf, endOfcountOf rằng rất thuận tiện để xác định để chúng có thể áp dụng cho cả mảng thô và vùng chứa thư viện chuẩn. Theo như tôi biết bộ ba này lần đầu tiên được xác định bởi Dietmar Kuehl. Trong C++ 0x startOfendOf hầu hết sẽ có sẵn dưới dạng std::beginstd::end.

Chúc mừng & hth.,

+2

+1: Thú vị! Có lý do nào để sử dụng '' thay vì ''? –

+0

Không phải là tôi có thể nghĩ đến; và tôi có thể nghĩ ra một số lý do để thích . –

+1

Đối với những gì nó ít có giá trị, đây là của tôi đi trên '' vs '' lý luận (lưu ý: Tôi thích bản thân biến thể C cũ): http://stackoverflow.com/questions/2118422/scope-of -c-library-in-cxh-vs-cx/2118718 # 2118718 –

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