2009-07-11 78 views
52

Là sizeof (enum) == sizeof (int), luôn luôn?Là sizeof (enum) == sizeof (int), luôn luôn?

  • Hoặc trình biên dịch có phụ thuộc không?
  • Có sai khi nói, vì trình biên dịch được tối ưu hóa cho độ dài từ (liên kết bộ nhớ) tức là y int là kích thước từ trên một trình biên dịch cụ thể? Nó có nghĩa là không có hình phạt xử lý nếu tôi sử dụng enums, vì chúng sẽ được liên kết từ?
  • Không tốt hơn nếu tôi đặt tất cả các mã trả lại trong một enum, vì tôi rõ ràng không lo lắng về các giá trị nó nhận được, chỉ có tên trong khi kiểm tra các loại trả về. Nếu đây là trường hợp wont #DEFINE được tốt hơn vì nó sẽ tiết kiệm bộ nhớ.

Thực tiễn thông thường là gì? Nếu tôi phải vận chuyển các kiểu trả về này qua mạng và một số xử lý phải được thực hiện ở đầu kia, bạn muốn enums/# define/const ints.

EDIT - Chỉ cần kiểm tra trên mạng, vì trình duyệt không liên kết tượng trưng cho macro, làm cách nào để gỡ lỗi sau đó, so sánh giá trị số nguyên với tệp tiêu đề?

Từ Đáp -Tôi đang thêm dòng dưới đây, như tôi cần clarifications-

"Vì vậy, nó là thực hiện xác định, và sizeof (enum) có thể bằng sizeof (char) , tức là 1. "

  • Không có nghĩa là trình biên dịch sẽ kiểm tra phạm vi giá trị trong enums và sau đó gán bộ nhớ. Tôi không nghĩ vậy, tất nhiên là tôi không biết. Ai đó có thể vui lòng giải thích cho tôi những gì là "có thể".
+0

Kiểm tra: http://stackoverflow.com/ câu hỏi/366017/what-is-the-size-of-an-enum-in-c Và điều này: http://bytes.com/groups/cpp/135139-sizeof-en um-sizeof-int – Macarse

+0

Từ net- trên một số diễn đàn, "Tôi nghĩ rằng một enum được coi là nhỏ như cần thiết để giữ tất cả các giá trị của nó, trong trường hợp này 1 byte." Có đúng không. –

+0

Nhờ tất cả những gì tôi đang học về những nghi ngờ hợp lý, điều mà tôi nghĩ chắc chắn sẽ giúp bạn có được khái niệm tốt hơn. –

Trả lời

31

Nó phụ thuộc vào trình biên dịch và có thể khác nhau giữa các enums. Sau đây là ngữ nghĩa

enum X { A, B }; 

// A has type int 
assert(sizeof(A) == sizeof(int)); 

// some integer type. Maybe even int. This is 
// implementation defined. 
assert(sizeof(enum X) == sizeof(some_integer_type)); 

Lưu ý rằng "một số loại nguyên" trong C99 cũng có thể bao gồm các loại số nguyên mở rộng (mà việc thực hiện, tuy nhiên, phải ghi lại, nếu nó cung cấp). Loại liệt kê là một số loại có thể lưu trữ giá trị của bất kỳ điều tra viên nào (AB trong trường hợp này).

Tôi không nghĩ rằng có bất kỳ hình phạt nào trong việc sử dụng liệt kê. Enumerators là các biểu thức không đổi không đổi (vì vậy bạn có thể sử dụng nó để khởi tạo các biến phạm vi tĩnh hoặc tệp, ví dụ) và tôi thích chúng thành các macro bất cứ khi nào có thể.

Các điều tra viên không cần bất kỳ bộ nhớ thời gian chạy nào. Chỉ khi bạn tạo một biến kiểu liệt kê, bạn có thể sử dụng bộ nhớ thời gian chạy. Chỉ cần nghĩ về các điều tra viên như là hằng số thời gian biên dịch.

Tôi chỉ sử dụng loại có thể lưu trữ giá trị của điều tra viên (tôi nên biết phạm vi giá trị thô trước đó), truyền tới nó và gửi qua mạng. Tốt hơn là loại có độ rộng cố định, chẳng hạn như int32_t, do đó, nó không đến xung đột khi các máy khác nhau có liên quan. Hoặc tôi sẽ in số, và quét nó ở phía bên kia, mà được thoát khỏi một số trong những vấn đề này.


Response to Chỉnh sửa

Vâng, trình biên dịch không cần phải sử dụng bất kỳ kích thước. Một điều dễ thấy là dấu hiệu của các giá trị quan trọng - các loại không dấu có thể có hiệu suất tăng đáng kể trong một số phép tính. Sau đây là hành vi của GCC 4.4.0 trên hộp của tôi

int main(void) { 
    enum X { A = 0 }; 
    enum X a; // X compatible with "unsigned int" 
    unsigned int *p = &a; 
} 

Nhưng nếu bạn gán một -1, sau đó GCC choses sử dụng int như kiểu mà X tương thích với

int main(void) { 
    enum X { A = -1 }; 
    enum X a; // X compatible with "int" 
    int *p = &a; 
} 

Sử dụng tùy chọn --short-enums của GCC, mà làm cho nó sử dụng loại nhỏ nhất vẫn phù hợp với tất cả các giá trị.

int main() { 
    enum X { A = 0 }; 
    enum X a; // X compatible with "unsigned char" 
    unsigned char *p = &a; 
} 
+0

Tôi nghĩ bây giờ, thay vì lưu trữ mỗi lệnh trong biến char chưa ký và so sánh nó với một giá trị, tôi sẽ lưu nó trong #define, vì nó luôn được thực hiện. Enums sẽ đối mặt với các vấn đề đặt hàng byte. Tôi nghĩ bây giờ tôi hiểu tại sao #define luôn được sử dụng cho các mã lỗi, tên tiểu bang, lệnh ... v.v. –

+9

Nó không hoàn toàn đúng sự thật không có sự khác biệt giữa enums và #defines: như bạn đã nói cho #defines trình biên dịch thậm chí không nhìn thấy mã thông báo ban đầu, vì nó được thay thế bằng giá trị thực của bộ tiền xử lý. Trình biên dịch không nhìn thấy enums mặc dù, và nếu bạn biên dịch mã với các biểu tượng gỡ lỗi, trình gỡ lỗi sẽ hiển thị cho bạn các nhãn được liệt kê thay vì giá trị của chúng, điều này sẽ giúp gỡ lỗi rất nhiều. – Metiu

19

C99, 6.7.2.2p4 nói

Mỗi kiểu liệt kê phải tương thích với char, một ký số nguyên loại, hoặc một unsigned loại số nguyên. Lựa chọn loại được xác định thực hiện, 108) nhưng phải có khả năng đại diện cho các giá trị của tất cả các thành viên của số . [...]

Footnote 108 cho biết thêm

An thực hiện có thể trì hoãn sự lựa chọn của nguyên loại cho đến khi tất cả các hằng liệt kê đã được nhìn thấy.

Vì vậy, nó là thực hiện xác định, và sizeof (enum) có thể là bằng sizeof (char), tức là 1.

Trong chosing kích thước của một số phạm vi nhỏ của số nguyên, có luôn một hình phạt. Nếu bạn làm cho nó nhỏ trong bộ nhớ, có lẽ là một hình phạt xử lý; nếu bạn làm cho nó lớn hơn, có một hình phạt không gian. Đó là một sự cân bằng không gian thời gian.

Mã lỗi thường là #defines, vì chúng cần phải được mở rộng: các thư viện khác nhau có thể thêm mã lỗi mới.Bạn không thể làm điều đó với enums.

+0

Điều đó không có nghĩa là người kiểm tra sẽ kiểm tra phạm vi của các giá trị trong enums, và sau đó gán bộ nhớ. Tôi không nghĩ như vậy, ofcourse tôi không biết :). Có thể một số xin vui lòng hiển thị giải thích những gì là "có thể" –

+0

"Trình biên dịch hiện" là một tuyên bố vô dụng. Có nhiều trình biên dịch trên thế giới, và một số làm theo cách đó, và một số khác làm theo cách khác (thậm chí trên cùng một phần cứng). Nếu bạn muốn biết trình biên dịch cụ thể làm gì, bạn phải đặt tên trình biên dịch (bao gồm cả phiên bản và CPU mục tiêu và hệ điều hành). Nó cũng có thể là * trình biên dịch * của bạn luôn luôn sử dụng int cho enums. –

+0

Câu trả lời thứ hai [ở đây] (http://stackoverflow.com/questions/366017/what-is-the-size-of-an-enum-in-c) đưa ra một phiên bản khác của cùng một tiêu chuẩn mà nó nói phải tương thích với 'int'. Phiên bản của anh ấy đã lỗi thời chưa (anh ấy liên kết với bản nháp) hay là của bạn? – Norswap

13

Là sizeof (enum) == sizeof (int), luôn luôn

Tiêu chuẩn ANSI C nói:

Mỗi kiểu liệt kê phải tương thích với char, một loại số nguyên đã ký hoặc loại số nguyên không dấu. Lựa chọn loại được xác định thực hiện. (6.7.2.2 Enumerationspecifiers)

Vì vậy, tôi sẽ lấy điều đó để có nghĩa là không.

Nếu đây là trường hợp không tốt hơn, vì nó sẽ tiết kiệm bộ nhớ.

Bằng cách nào sử dụng định nghĩa tiết kiệm bộ nhớ bằng cách sử dụng enum?Một enum chỉ là một kiểu cho phép bạn cung cấp thêm thông tin cho trình biên dịch. Trong thực tế kết quả thực thi, nó chỉ được chuyển sang một số nguyên, giống như trình tiền xử lý chuyển đổi macro được tạo với #define vào giá trị của nó.

Thực tiễn thông thường là gì. Nếu tôi phải vận chuyển các loại trả lại này qua mạng và một số quá trình xử lý phải được thực hiện ở đầu kia

Nếu bạn dự định vận chuyển giá trị qua mạng và xử lý chúng ở đầu bên kia, bạn nên xác định giao thức. Quyết định kích thước theo bit của mỗi loại, endianess (theo thứ tự các byte) và đảm bảo bạn tuân thủ điều đó trong cả khách hàng và mã máy chủ. Cũng không chỉ giả định rằng bởi vì nó xảy ra để làm việc, bạn đã có nó đúng. Nó chỉ có thể là endianess, ví dụ, trên các nền tảng máy khách và máy chủ bạn đã chọn phù hợp, nhưng điều đó có thể không phải lúc nào cũng đúng.

+0

có đó là mối quan tâm, tôi đã chuyển một số giá trị được sử dụng như lệnh qua mạng, và tôi muốn làm cho hiệu quả và mạnh mẽ nhất có thể, tức là yi cần ý kiến ​​gì để sử dụng cho lệnh #defines hoặc enums, phạm vi lệnh sẽ không được nhiều hơn 20 lệnh, do đó, theo tất cả trong giới hạn char. Tôi nghĩ rằng tôi sẽ đăng nó như một câu hỏi mới, tôi sẽ nhận được một phản ứng tốt hơn. –

+1

Điều đơn giản nhất để làm là chỉ cần sử dụng một ký tự chưa ký. Bạn không phải lo lắng về endianess hoặc mã hóa theo cách đó. – IRBMe

+0

có thể bạn có thể thêm một tham chiếu đến [Tôi có nên sử dụng cstdint?] (Https://stackoverflow.com/q/6144682/2932052) cho phần mạng – Wolf

3

Trên một số trình biên dịch, kích thước của một enum tùy thuộc vào số lượng mục nhập trong Enum. (ít hơn 255 Entrys => Byte, hơn 255 Entrys int) Nhưng điều này phụ thuộc vào Trình biên dịch và Cài đặt trình biên dịch.

+0

là có anyway tôi có thể ép buộc điều này. Một đầu vào tốt đẹp nhờ mặc dù. –

+0

Vì những vấn đề này trong dự án của chúng tôi (chúng tôi phải sử dụng trình biên dịch C cũ thực sự), chúng tôi quyết định không sử dụng enum. Nhưng để xác định mọi thứ với #define – nuriaion

4

số

Ví dụ: The CodeSourcery compiler

Khi bạn xác định một enum như thế này:

enum MyEnum1 { 
A=1, 
B=2, 
C=3 
}; 
// will have the sizeof 1 (fits in a char) 

enum MyEnum1 { 
A=1, 
B=2, 
C=3, 
D=400 
}; 
// will have the sizeof 2 (doesn't fit in a char) 

Details từ danh sách gửi thư của họ

+0

nếu đó là trường hợp tuyệt vời của nó. –

+3

đó là không đúng .... nó thực hiện phụ thuộc .... cả hai mã cho đầu ra như 4 trên system.Platform của tôi - Ubuntu 10.04 (32-bit), trình biên dịch gcc –

+0

Không phải là một ví dụ xấu, nhưng cả hai liên kết http: // www.codesourcery.com/sgpp (1) và http://www.codesourcery.com/archives/arm-gnu/msg02684.html (2) bị hỏng. (hy vọng cập nhật sửa chữa.) – Wolf

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