2016-07-06 15 views
6

Tôi hiện đang sử dụng const tĩnh trong mã của tôi thay vì sử dụng 'số ma thuật' được đề cập trong "static const" vs "#define" vs "enum".Điều gì sẽ sử dụng thay cho số ma thuật trong C

void checkInvalidResponse (uint8_t response) 
{ 
    static const uint8_t INVALID_RESP = 0xFF; 

    if (response == INVALID_RESP) 
    { 
     /* Code for invalid response */ 
    } 
} 

Tôi, tuy nhiên, nghĩ rằng sử dụng const tĩnh sẽ tiêu thụ bộ nhớ trong mã được biên dịch cho INVALID_RESP. Tuyên bố cũng sẽ dịch sang mã máy thực hiện LOAD từ bộ nhớ theo sau so sánh, thay vì so sánh với một giá trị được cung cấp như là một phần của lệnh. Điều này có đúng không? Nếu vậy, thì giải pháp này sẽ không tối ưu về tốc độ và bộ nhớ phải không?

Tôi hiện đang thay đổi mã để sử dụng # định nghĩa

void checkInvalidResponse (uint8_t response) 
{ 
    #define INVALID_RESP 0xFF 

    if (response == INVALID_RESP) 
    { 
     /* Code for invalid response */ 
    } 
} 

Tuy nhiên, vì #define không có một phạm vi, hành vi của các khía cạnh cắt-và-dán của #define sẽ phù hợp trên nhiều trình biên dịch? Ví dụ: nếu INVALID_RESP được xác định lại sau, liệu có bất kỳ mã nào trong các dòng theo định nghĩa lại sử dụng giá trị mới không?

Một cách tiếp cận khác mà tôi đã xem xét là sử dụng các bảng liệt kê.

void checkInvalidResponse (uint8_t response) 
{ 
    typedef enum 
    { 
     INVALID_RESP = 0xFF 
    } resp_t; 

    if ((resp_t)response == INVALID_RESP) 
    { 
     /* Code for invalid response */ 
    } 
} 

Tuy nhiên, việc sắp xếp vào một enum sẽ phân bổ nhiều bộ nhớ hơn cần thiết (Bộ xử lý sẽ thực hiện so sánh 32 bit (?) Thay vì so sánh 8 bit).

Phương pháp tốt nhất để sử dụng thay vì sử dụng số ma thuật trong mã là gì?

+1

Bạn có thực sự lo lắng về loại cơ sở enum dài hơn 1 byte không? –

+1

Người thông minh đang gợi ý consts trên '# define' ở mọi nơi có thể. –

+0

Bạn có thể 'undef' định nghĩa' #', nơi bạn quyết định rằng bạn đang thực hiện với giá trị đó ... – sps

Trả lời

3

Tôi nghĩ rằng trong mọi trường hợp, trình biên dịch, ít nhất với -O2 bật, sẽ tạo ra cùng một mã. Nó đã nhận được khá khó khăn để lừa các trình biên dịch vào làm những điều ngu ngốc.

Thông thường, các số ma thuật được xác định trong một tiêu đề phổ biến và được sử dụng khi cần trong toàn bộ mã.

Câu hỏi lớn hơn cho bạn là, có quan trọng không? Đây có phải là cái gì đó trong con đường quan trọng của mã của bạn, và một cái gì đó bạn sẽ làm một tỷ lệ rất cao của thời gian? Với cái tên, tôi đoán là không.

Di chuyển định nghĩa sang tệp tiêu đề sẽ làm cho mã của bạn bớt mất tập trung. Trong checkInvalidResponse, người đọc không thể quan tâm chính xác hơn những gì được đại diện bởi INVALID_RESPONSE, chỉ rằng thử nghiệm vượt qua hoặc không thành công.

0

enum được đảm bảo theo tiêu chuẩn để hỗ trợ tối đa unsigned int chiều rộng.

Nếu bạn sử dụng #define không có đặc tả ngầm về chiều rộng vì trình biên dịch trước sẽ chỉ thay thế ký hiệu bằng số (hoặc bất kỳ điều gì khác được xác định), để bạn có thể nối L vào cuối số và đảm bảo của bạn long giá trị.

Thẳng thắn mà nói, tôi chưa bao giờ có sử dụng cho enums lớn hơn số nguyên bản thân mình ...

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.7.2.2 specifiers Enumeration
[...]
chế
Khái niệm đó xác định giá trị của một hằng số liệt kê phải là một biểu thức hằng số nguyên có giá trị biểu diễn như một int.
[...]
Mỗi loại được liệt kê phải tương thích với char, 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, nhưng phải có khả năng biểu diễn các giá trị của tất cả các thành viên của điều tra.

1

Trong ngôn ngữ C const thực thể không phải là hằng số ở cấp độ ngôn ngữ, giới hạn đáng kể khả năng sử dụng của const để xác định hằng số tệp kê khai. Lưu ý rằng đây không phải là về hiệu quả của mã được tạo ra, đó là về tính hợp lệ cơ bản ("khả năng tương thích") của mã: trong ngôn ngữ C const thực thể đơn giản là không được phép trong các ngữ cảnh yêu cầu hằng số.

Vì lý do này bằng ngôn ngữ C phương pháp chỉ thực sự phổ biến và linh hoạt để xác định hằng số biểu hiện là C preprocessor (tức #define), với enum là một thay thế vialble, nhưng chỉ khi nó được áp dụng (một nhược điểm đáng kể của enum hằng trong C là việc họ vô điều kiện đã ký loại int).

Chỉ cần sử dụng #define và không cố gắng "phạm vi" các hằng số. Có bất kỳ điểm nào trong việc làm như vậy. Nhưng nếu vì một lý do nào đó bạn cần phải hạn chế phạm vi của hằng số #define 'd, bạn luôn có thể sử dụng #undef cho mục đích đó.

+0

Bạn có thể sao lưu điều này không. Theo như tôi nhớ, gcc đặt liên tục trong phần .text – doron

+1

@ doron: Nó không phải là nơi trình biên dịch đặt chúng. Đó là về thực tế rằng trong ngôn ngữ C 'const' thực thể không đủ điều kiện như là ngôn ngữ" hằng số ". Bạn không được phép sử dụng các thực thể 'const' trong nhãn' case', độ rộng trường bit, kích thước mảng không VLA vv Ngôn ngữ cấm nó và mã đơn giản sẽ không biên dịch. Chủ đề đã được bao phủ bởi các câu trả lời được liên kết trong các nhận xét. OP sử dụng một ví dụ không đại diện với 'if', không yêu cầu hằng số.Nhưng nếu họ sử dụng câu lệnh 'switch/case' thay vào đó, vấn đề với' const' sẽ ngay lập tức trở nên rõ ràng. – AnT

+0

Cảm ơn vì điều đó. Đây là một sự khác biệt bất ngờ trong C và C++ đối với tôi. – doron

0

Điều này tất cả sẽ là trình biên dịch và nền tảng cụ thể. Và trừ khi bạn thực sự cần phải sqeeze một vài byte ra để phù hợp trong một ROM, không thực sự quan trọng. Sử dụng trình biên dịch hầu như luôn ít lỗi hơn so với bộ tiền xử lý để gắn bó với các const.

Cũng lưu ý rằng trình biên dịch luôn được phép nội tuyến nếu nó có ý nghĩa hơn.

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