2010-02-22 42 views
42

Trong C, tôi có thích hằng số hơn định nghĩa không? Gần đây tôi đã đọc rất nhiều mã và tất cả các ví dụ đều sử dụng nhiều định nghĩa.Tôi có muốn các hằng số xác định không?

+17

Hãy cảnh giác với hội chứng Stockholm! – Potatoswatter

+0

[Câu trả lời này] (http://stackoverflow.com/a/1674459/2235567) có liên quan. –

+0

có thể trùng lặp của ["const tĩnh" và "#define" trong C] (http://stackoverflow.com/questions/1674032/static-const-vs-define-in-c) –

Trả lời

92

Không, nói chung bạn không nên sử dụng các đối tượng đủ điều kiện trong C để tạo các hằng số tên. Để tạo hằng số có tên trong C, bạn nên sử dụng macro (#define) hoặc enums. Trong thực tế, ngôn ngữ C không có hằng số, theo nghĩa bạn có vẻ ngụ ý.(C là khác nhau đáng kể từ C++ trong lĩnh vực này)

Trong ngôn ngữ C các khái niệm của liên tụcliên tục biểu được định nghĩa rất khác so với C++. Trong C hằng số có nghĩa là giá trị bằng chữ, như 123. Dưới đây là một số ví dụ về hằng trong C

123 
34.58 
'x' 

hằng số trong C có thể được sử dụng để xây dựng biểu thức hằng số. Tuy nhiên, vì các đối tượng đủ điều kiện của bất kỳ loại nào không phải là một hằng số trong C, chúng không thể được sử dụng trong các biểu thức liên tục, và do đó, bạn không thể sử dụng các đối tượng đủ điều kiện.

Ví dụ, sau đây không phải là một hằng số

const int C = 123; /* C is not a constant!!! */ 

và kể từ khi trên C không phải là một hằng số, nó không thể được sử dụng để khai báo một kiểu mảng trong phạm vi tập tin

typedef int TArray[C]; /* ERROR: constant expression required */ 

Nó không thể được sử dụng làm nhãn trường hợp

switch (i) { 
    case C: ; /* ERROR: constant expression required */ 
} 

Nó không thể được sử dụng làm bit-fi chiều rộng lĩnh

struct S { 
    int f : C; /* ERROR: constant expression required */ 
}; 

Nó không thể được sử dụng như một initializer cho một đối tượng với thời gian lưu trữ tĩnh

static int i = C; /* ERROR: constant expression required */ 

Nó không thể được sử dụng như một enum initializer

enum { 
    E = C /* ERROR: constant expression required */ 
}; 

tức là nó không thể được sử dụng bất cứ nơi nào cần có hằng số.

Điều này có vẻ phản trực giác, nhưng đây là cách C ngôn ngữ được xác định.

Đây là lý do tại sao bạn thấy rất nhiều #define -s trong mã bạn đang làm việc. Một lần nữa, trong ngôn ngữ C const-đủ điều kiện đối tượng có sử dụng rất hạn chế. Về cơ bản chúng hoàn toàn vô dụng như "hằng số", đó là lý do tại sao trong ngôn ngữ C bạn về cơ bản buộc phải sử dụng #define hoặc enums để khai báo hằng số thực. Tất nhiên, trong các tình huống khi một đối tượng đủ điều kiện làm việc cho bạn, tức là nó làm những gì bạn muốn nó làm, nó thực sự vượt trội so với các macro theo nhiều cách, vì nó là phạm vi và gõ. Bạn có lẽ nên thích các đối tượng như vậy khi áp dụng, tuy nhiên trong trường hợp chung bạn sẽ phải tính đến các hạn chế trên.

+16

+1 cho sự hiểu biết và khớp đúng với sự khác biệt C/C++, một điểm dường như bị mất trên nhiều người. – asveikau

+1

Câu trả lời hay. Cảm ơn bạn đã nêu bật vấn đề với các biến 'đủ điều kiện để khai báo kích thước mảng. –

+2

+1 Wow, câu trả lời tuyệt vời – helpermethod

9

Các hằng số nên được ưu tiên hơn define s. Có một số ưu điểm:

  • Loại an toàn. Trong khi C là một yếu kém kiểu languaged, sử dụng một define mất tất cả các loại an toàn, mà sẽ cho phép trình biên dịch để nhận các vấn đề cho bạn.

  • Dễ gỡ lỗi. Bạn có thể thay đổi giá trị hằng số thông qua trình gỡ lỗi, trong khi define s được tự động thay đổi trong mã bằng bộ xử lý trước thành giá trị thực tế, có nghĩa là nếu bạn muốn thay đổi giá trị cho mục đích thử nghiệm/gỡ lỗi, bạn cần phải biên dịch lại.

+2

Tôi đã tìm thấy rằng nhiều trình biên dịch sẽ bake 'const static ints' vào các hằng số opcode ngay lập tức, giống như #defines, làm cho chúng không thể thay đổi trong trình gỡ rối. – Crashworks

+0

@Crashworks - điều đó có phụ thuộc vào mức tối ưu hóa không? – LeopardSkinPillBoxHat

+0

ngay cả khi tối ưu hóa trình biên dịch bị vô hiệu hóa? –

1

Nếu nó không được xác định theo chương trình, tôi sử dụng #define. Ví dụ: nếu tôi muốn tất cả các đối tượng giao diện người dùng của mình có cùng khoảng cách giữa chúng, tôi có thể sử dụng #define kGUISpace 20.

2

Xác định là một phần của ngôn ngữ dài hơn hằng số, vì vậy nhiều mã cũ hơn sẽ sử dụng chúng vì xác định cách duy nhất để hoàn thành công việc khi mã được viết. Đối với mã gần đây hơn, nó có thể chỉ đơn giản là một vấn đề của thói quen lập trình viên.

Hằng số có loại cũng như giá trị, vì vậy chúng sẽ được ưu tiên khi giá trị của bạn có giá trị, nhưng không phải khi giá trị không có kiểu (hoặc đa hình).

7

Có lẽ tôi đã sử dụng chúng sai, nhưng ít nhất trong gcc, bạn không thể sử dụng hằng số trong trường hợp báo cáo.

const int A=12; 
switch (argc) { 
    case A: 
    break; 
} 
3

xác định có thể được sử dụng cho nhiều mục đích (rất lỏng lẻo) và nên tránh nếu bạn có thể thay thế bằng const, xác định biến và bạn có thể làm được nhiều hơn.

Trong những trường hợp như dưới đây, xác định phải được sử dụng

  • chỉ thị chuyển đổi
  • thay vào dòng nguồn của bạn
  • macro đang

Một ví dụ mà bạn phải sử dụng định nghĩa trên const là khi bạn có số phiên bản nói 3 và bạn muốn phiên bản 4 bao gồm một số phương thức không có sẵn trong phiên bản 3

#define VERSION 4 
... 

#if VERSION==4 
    ................ 
#endif 
5

Rất nhiều người ở đây đang cung cấp cho bạn lời khuyên "kiểu C++". Một số thậm chí nói rằng các đối số C++ áp dụng cho C. Đó có thể là một điểm công bằng. (Cho dù đó là hoặc không cảm thấy loại chủ quan.) Những người nói const đôi khi có nghĩa là một cái gì đó khác nhau trong hai ngôn ngữ cũng chính xác.

Nhưng đây chủ yếu là những điểm nhỏ và cá nhân, tôi nghĩ sự thật có hậu quả tương đối nhỏ để đi theo một trong hai cách.Đó là vấn đề về phong cách, và tôi nghĩ rằng những nhóm người khác nhau sẽ cho bạn những câu trả lời khác nhau.

Về mặt sử dụng phổ biến, mức sử dụng lịch sử và phong cách phổ biến nhất, trong C, sẽ điển hình hơn khi xem #define. Sử dụng C++ isms trong mã C có thể đi ra như là lạ đối với một phân đoạn hẹp nhất định của C coders. (Bao gồm cả tôi, vì vậy đó là nơi thiên vị của tôi nằm.)

Nhưng tôi ngạc nhiên không ai đề xuất giải pháp nền tảng trung bình, "cảm thấy đúng" ở cả hai ngôn ngữ: nếu nó phù hợp với một nhóm hằng số nguyên, sử dụng an enum.

1

Ngoài những lý do tuyệt vời do AndreyT đưa ra để sử dụng DEFINES thay vì các hằng số trong mã "C", có một lý do thực dụng khác để sử dụng DEFINES.

DEFINES dễ định nghĩa và sử dụng các tệp tiêu đề (.h), là nơi mà bất kỳ trình mã hóa C có kinh nghiệm nào mong đợi tìm các hằng số được xác định. Việc xác định các const trong các tệp tiêu đề không hoàn toàn dễ dàng như vậy - nhiều mã hơn để tránh các định nghĩa trùng lặp, v.v.

Các đối số "typesafe" là hầu hết các trình biên dịch sẽ nhận các lỗi rõ ràng như assing string và int, hoặc , sẽ "làm điều đúng" trên một chút không khớp như gán một số nguyên cho một phao.

1

Macro (định nghĩa) có thể được sử dụng bởi bộ xử lý trước và tại thời gian biên dịch, hằng số không thể.

Bạn có thể thực hiện kiểm tra thời gian biên dịch để đảm bảo macro nằm trong phạm vi hợp lệ (và #error hoặC#fatal nếu không). Bạn có thể sử dụng giá trị mặc định cho macro nếu macro chưa được xác định. Bạn có thể sử dụng macro trong kích thước của một mảng.

Một trình biên dịch có thể tối ưu hóa với các macro tốt hơn so với những gì có thể với các hằng số:

const int SIZE_A = 15; 
#define SIZE_B 15 

for (i = 0; i < SIZE_A + 1; ++i); // if not optimized may load A and add 1 on each pass 
for (i = 0; i < SIZE_B + 1; ++i); // compiler will replace "SIZE_B + 1" with 16 

Hầu hết các công việc của tôi là với các bộ xử lý nhúng mà không có trình biên dịch tối ưu hóa tuyệt vời. Có thể gcc sẽ xử lý SIZE_A như macro ở cấp độ tối ưu hóa nào đó.

5

Mặc dù câu hỏi này là cụ thể cho C, tôi đoán nó là tốt để biết điều này:

#include<stdio.h> 
int main() { 
    const int CON = 123; 
    int* A = &CON; 
    (*A)++; 
    printf("%d\n", CON); // 124 in C 
} 

công trình trong C, nhưng không phải trong C++

Một trong những lý do để sử dụng #define là để tránh những điều như vậy để làm rối tung mã của bạn, đặc biệt nó là sự kết hợp giữa C và C++.

+0

+1 Mẹo hay, không biết điều đó. – helpermethod

+1

Không sử dụng con trỏ để thay đổi chỉ đọc int trong C undefined hành vi? –

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