sizeof style: sizeof (type) hay sizeof biến?


22

Tôi đã thấy hai kiểu sử dụng sizeofcho các hoạt động liên quan đến bộ nhớ (chẳng hạn như trong memsethoặc malloc):

  • sizeof(type)
  • sizeof variable hoặc là sizeof(variable)

Bạn thích kiểu nào hơn, hoặc bạn sẽ sử dụng kết hợp cả hai kiểu, và khi nào bạn sẽ sử dụng từng kiểu? Những ưu và nhược điểm của từng phong cách và khi bạn sử dụng chúng là gì?

Ví dụ, tôi có thể thấy các cặp tình huống sau đây trong đó một kiểu giúp và kiểu kia không:

Khi bạn nhận được con trỏ sai hướng:

type *var;
...
memset(var, 0, sizeof var);    /* oops */

Khi loại thay đổi:

new_type var;    /* changed from old_type to new_type */
...
memset(&var, 0, sizeof(old_type));    /* oops */

Câu trả lời:


30

Tôi lo sizeof(variable)lắng hơn sizeof(type). Xem xét:

int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));

so với

int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));

Trong trường hợp đầu tiên, thật dễ dàng để xác minh rằng các kích thước phù hợp đang được chuyển đến memset. Trong trường hợp thứ hai, bạn cần liên tục xem xét các phần trên cùng và dưới cùng để đảm bảo bạn nhất quán.


4
Ngoài ra, nếu bạn thay đổi loại biến, mã giả định loại sẽ phải thay đổi. Tôi nghĩ tốt hơn là nên viết đúng mã với ít sự phụ thuộc vào loại càng tốt. (Tôi bị ảnh hưởng bởi một dự án chuyển đổi lớn 16 bit thành 32 bit vào ban ngày.)
Gort the Robot

Điều này là thích hợp hơn để làm việc với các mảng C, nơi không phổ biến để tạo một typedef, nhưng sử dụng những thứ như mảng char [MAX_SIZE];
mattnz

@ vy32: Sai 1: "sizeof (mảng) KHÔNG trả về kích thước của mảng ... kích thước của con trỏ cho mảng" - nếu arraythực sự là một mảng C, sau đó sizeof(array)trả về số byte cần thiết để lưu trữ các phần tử mảng . Nếu arraylà một con trỏ tới phần tử đầu tiên của mảng C bị phân rã, thì câu lệnh của bạn được giữ. Truyền một mảng C làm đối số hàm làm cho nó trông giống như một con trỏ trong hàm - tất cả thông tin chứng minh nó là một mảng, giống như kích thước của nó, bị mất. Đó là lý do tại sao nó bị phân rã . Sai 2: "mảng không thực sự tồn tại trong C; ... chỉ đơn giản là cú pháp đường cho con trỏ."
Johann Gerell

9

Sở thích (như mọi khi) là phản ánh ý định của bạn trực tiếp nhất có thể.

Là ý định hoạt động chống lại bộ nhớ của một biến hiện có? Nếu vậy, sau đó sử dụng sizeof(variable), vì điều này thể hiện càng gần càng tốt rằng đó là bộ nhớ của chính biến mà bạn quan tâm.

Là ý định thực hiện một số tính toán về loại, ví dụ để xác định dung lượng bộ nhớ sẽ được phân bổ cho một thể hiện mới? Nếu vậy thì sử dụng sizeof(type).

Đó là, tôi thích

struct foo *bar;
bar = (struct foo *) malloc(sizeof(struct foo));

kết thúc

bar = (struct foo *) malloc(sizeof(*bar));

vì trường hợp sau có vẻ như bạn đang cố truy cập vào một biến không tồn tại.

Mặt khác, tôi thích

char Buffer[256];
memset(Buffer, 0, sizeof(Buffer));

kết thúc

char Buffer[256];
memset(Buffer, 0, 256 * sizeof(char));

vì mục đích rõ ràng là không điền vào nội dung của biến, vì vậy đó là biến chúng ta nên thao tác. Cố gắng sử dụng siêu dữ liệu loại chỉ gây nhầm lẫn mọi thứ, ở đây.



Tôi luôn luôn làm thế, nhưng đó là vấn đề sở thích cá nhân. Tôi coi đó void *là tự động được chuyển sang các loại con trỏ khác là không phù hợp.
Aidan Cully

3

Tôi sẽ rất thích sizeof(type)hơn sizeof variable. Mặc dù nó buộc bạn phải lo lắng thêm về các loại và thực hiện thay đổi hơn, nó giúp bạn tránh những sai lầm trỏ gián tiếp, trong đó xếp hạng trong số các nguyên nhân phổ biến nhất của lỗi trong C .

Tôi sẽ không lo lắng quá nhiều về các lỗi mà loại trong sizeof(type)đó được thay đổi; Bất cứ khi nào bạn thay đổi loại biến, bạn nên quét nhanh để xem biến đó được sử dụng ở đâu và nếu bạn cần thay đổi bất kỳ sizeof(type)câu lệnh nào . Mặc dù luôn có cơ hội mắc phải lỗi này, nhưng nó có rủi ro thấp hơn nhiều so với sai lầm của con trỏ.

Một lợi thế của sizeof variablemảng là, nhưng trong thực tế tôi đã thấy rằng việc truyền các mảng dưới dạng cặp đầu tiên / len là phổ biến hơn nhiều (trong trường hợp chỉ sử dụng độ dài), cộng với nó cũng rất dễ bị sai kích thước do phân rã mảng / con trỏ, như trong ví dụ này:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}

2
"Quét nhanh để xem biến đó được sử dụng ở đâu .... luôn có khả năng xảy ra lỗi này" - với tôi đây là mối nguy hiểm lớn nhất khi thực hiện sizeof (loại), đó là lý do tại sao tôi luôn thực hiện sizeof (biến). Bởi vì kết quả cuối cùng của mối nguy hiểm này là mọi thứ vẫn có thể được biên dịch và ngay cả khi bạn mắc một lỗi, nó có thể khiến bạn mất hơn một năm hoặc các sự cố ngẫu nhiên và hỏng bộ đệm trước khi bạn bắt được nó. Và tôi không thể thực hiện kết nối (rõ ràng cửa sổ thời gian của tôi cho mỗi câu hỏi là khoảng 30 giây) giữa câu hỏi này và "lỗi dẫn hướng con trỏ".
DXM

@DXM Với toán hạng sizeof, nếu đó là một giá trị thì đó là sizeof var; nếu đó là một con trỏ nó sizeof *var. Đây cũng là một cái gì đó mà mọi người có thể nhận được sai, và trình biên dịch sẽ vui vẻ nhận nó mà không có khiếu nại. Tôi cho rằng những sai lầm này khó phát hiện hơn nhiều, và phổ biến hơn là những sai lầm với sizeof(type)hình thức.
congusbongus

1
Cả hai bên phải của bạn - Kiểu C và toán tử sizeof bị hỏng cơ bản và sẽ không bao giờ đáng tin cậy, không có gì bạn làm như một lập trình viên có thể sửa chữa nó.
mattnz

Khi bài viết được gắn thẻ C, việc đăng mã C có nhiều thông tin mà mã C ++ thích mat3_t::mat3_t(...).
chux - Phục hồi Monica

0

Mục đích là để loại bỏ sự dư thừa. Nếu bạn sử dụng sizeof cho một hoạt động liên quan đến một biến, thì rõ ràng bạn sẽ phản ánh điều đó trong sizeof. Có, bạn có thể gây rối như trong ví dụ đầu tiên, nhưng cách chữa không phải là sử dụng loại, mà là * var, khớp chính xác với mục tiêu.

Để giảm thiểu những vấn đề như vậy, thông thường nên sử dụng macro, mẫu và các công cụ tương tự được đào tạo cho trường hợp sử dụng thay vì kích thước trần trụi.

Xem macro XÓA của tôi được sử dụng riêng thay vì bộ nhớ trần. Đã lưu ass của tôi nhiều lần trong các trường hợp lỗi chính tả hoặc khi một nội dung cấu trúc nhặt một vectơ hoặc chuỗi ...


Các macro như vậy là thứ đã tạo cho chương trình Macro của C một tên xấu ......
mattnz

@mattnz: vui lòng hiển thị thay thế tốt hơn. Thật dễ dàng để nói những thứ trừu tượng hơn là tạo ra các chương trình thực sự hoạt động
Balog Pal

1
Macro được liên kết là C ++ và bài đăng này được gắn thẻ 'C' (Chúng là các ngôn ngữ khác nhau), Ada sẽ là đề xuất của tôi.
mattnz

@mattnz: và cùng một chủ đề cho thấy cách thực thi theo cách tương tự đối với C. Bạn dường như hoàn toàn bỏ lỡ vấn đề, đó không phải là triển khai nội dung thực tế nhưng sử dụng an toàn hơn so với nội dung thô. Cách Btw cũng có thể đọc được.
Balog Pal

0

Logic kinh doanh xác định sự lựa chọn của bạn.

  1. Nếu mã của bạn đề cập đến một biến cụ thể và không có biến này, mã của bạn sẽ không có ý nghĩa - chọn sizeof(var)

  2. Nếu bạn mã giao dịch với một tập hợp các biến với loại cụ thể - chọn sizeof(type). Thông thường bạn cần điều này nếu bạn có một typedefđịnh nghĩa nhiều biến mà bạn xử lý khác nhau dựa trên loại của chúng (ví dụ: tuần tự hóa). Bạn có thể không biết biến nào trong số các biến này sẽ vẫn còn trong các phiên bản mã trong tương lai, vì vậy việc chọn loại làm đối số là chính xác về mặt logic. Ngay cả việc thay đổi như vậy typedefsẽ không ảnh hưởng đến dòng sizeof của bạn.


-1

Tùy thuộc vào mục đích sizeof (biến) có thể là giải pháp tốt nhất. Theo cách đó, bạn có thể thay đổi loại biến nếu cần, mà không cần sửa tất cả các mục cho loại. Nhưng một lần nữa, nó phụ thuộc vào mục tiêu của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.