2009-09-13 42 views
7

Tôi đã được thông báo rằng nếu tôi đang mã hóa trong ANSI-C để khai báo theo thứ tự các biến sẽ được sử dụng, hãy xác nhận rằng các con trỏ không rỗng và các chỉ số nằm trong giới hạn, và để khởi tạo ngay trước khi sử dụng biến.C: Hành vi của từ khóa `const`

Nếu tôi khai báo một const, tôi có thể khởi tạo nó sau một khối xác nhận và mã không? Trong việc khởi tạo Java cuối cùng phải xảy ra khi khai báo, nhưng nó có nhất quán thông qua triển khai ANSI-C mà tôi có thể khởi tạo một const một lần nhưng không nhất thiết tại thời điểm khai báo không? Các biến số

Trả lời

9

Trình biên dịch Java có một số lượng nhỏ của logic dòng chảy để cho phép bạn initalise final biến sau khi khai báo của họ.Đây là hợp pháp Java:

final int something; 

if (today == Friday) 
    something = 7; 
else 
    something = 42; 

Java sẽ phát hiện nếu bất kỳ chi nhánh nào để giá trị cuối cùng không được xác định. Nó sẽ không phân tích các điều kiện, vì vậy đây không phải là hợp pháp Java, mặc dù nó là một cách logic tương tự:

final int something; 

if (today == Friday) 
    something = 7; 

if (today != Friday) 
    something = 42; 

Trong ANSI C89, const biến (trừ extern) phải được khởi tạo trong tuyên bố họ được khai báo trong.

const int something = (today == Friday) ? 7 : 42; 

các extern sửa đổi trên một tuyên bố nói với trình biên dịch mà biến được khởi tạo trong một đơn vị complation khác nhau (hoặc ở nơi khác trong đơn vị biên dịch này).

Trong ANSI C99, bạn có thể trộn các khai báo và mã, để bạn có thể khai báo và khởi tạo biến số const sau một khối xác nhận và mã. Tính di động của năm 1999 ANSI C vẫn là một vấn đề.

Một tác phẩm xung quanh cho C89 cần lưu ý rằng các quy tắc cho các tờ khai trước công việc mã ở phạm vi khối chứ không phải là phạm vi chức năng, vì vậy bạn có thể làm điều này:

#include<stdio.h> 

int main (void) 
{ 
    printf ("wibble\n"); 

    { 
     const int x = 10; 

     printf ("x = %d\n", x); 
    } 

    return 0; 
} 
+1

@Pete: 2x Bài học kinh nghiệm. –

+1

Trên thực tế, bạn có thể khai báo các biến * global * const ngoài global mà không cần khởi tạo chúng. 'const int a;' được gọi là "định nghĩa dự kiến", hoặc một cái gì đó tương tự.Nếu biến sau đó được định nghĩa rõ ràng, thì nó được coi như một khai báo. Nếu không, đó là định nghĩa. Vì vậy, bạn có thể có 'const int a;' trong một tiêu đề, và sau đó 'const int a = 12;' trong tệp .c. Không phải là bạn thường muốn, vì bạn có nguy cơ quên định nghĩa và kết thúc với 'a' là 12 trong một số đơn vị biên dịch và 0 trong số khác ... –

+0

@onebyone: Trên thực tế," định nghĩa dự kiến ​​"không dẫn đến khác nhau giá trị trong các đơn vị biên dịch khác nhau. Thử biên dịch "int x;" trong một tệp và "int x = 1;" trong một cái khác. Biến x chứa 1 trong cả hai tệp sau khi liên kết (với tất cả các trình biên dịch mà tôi đã thử). Đây là hành vi được triển khai rộng rãi, mặc dù tôi không đọc C99 như chỉ định chính xác điều này. –

3

const là chỉ đọc và phải được khởi tạo khi chúng được xác định.

Mã này tạo ra error: assignment of read-only variable 'foo' (gcc4):

const int foo; 
foo = 4; 

Cùng đi với con trỏ const (lưu ý ở đây: const int * không phải là một con trỏ const, nhưng một con trỏ đến const):

int * const foo; 
foo = 4; 
+0

Ví dụ cuối cùng cần * foo = 4; để tạo lỗi? Bởi vì gán 4 sẽ đơn giản là sử dụng một giá trị con trỏ không ... –

+0

Phụ thuộc vào ý nghĩa của lỗi. 'foo = 4' là một lỗi biên dịch vì foo là const. '* foo = 4' là một lỗi thời gian chạy (và hy vọng là một cảnh báo thời gian biên dịch) vì foo chưa được khởi tạo (hoặc được khởi tạo thành NULL nếu toàn cầu). –

1

Nếu bạn đang nói đến việc tách một định nghĩa

const int x = 2; 

thành hai phần:

const int x; 

x=2; 

Tôi sợ rằng không thể ở C.

Nếu tôi là bạn, tôi sẽ cố gắng để đảm bảo rằng tôi hiểu được mục đích của các quy tắc mã hóa mà bạn mô tả. Tôi nghi ngờ các quy tắc mã hóa sane sẽ ngăn chặn việc khởi tạo biến (ngay cả các biến không phải const).

Đáp lại ý kiến ​​khác nhau:

const int * p; 

KHÔNG phải là một lời tuyên bố của một biến const. Nó là một khai báo của một biến con trỏ không const đến một const int.

Bạn có thể tuyên bố

extern const int x; 

nhưng bạn vẫn có thể không khởi tạo x sau khi đã mã, kiểm tra khẳng định, thực hiện ...

+0

+1. Có lẽ ý định "khởi tạo ngay trước khi sử dụng" là (1) sao cho giá trị ban đầu gần với mã dựa vào nó, và/hoặc (2) nếu khởi tạo không hoạt động đôi khi có thể tránh được, đặt nó gần sử dụng đầu tiên là quy tắc tốt nhất để tối đa hóa khả năng tránh điều đó. Vì vậy, bạn phải cân nhắc hai thứ đó dựa vào giá trị của việc đánh dấu nó. –

+0

Vâng, nó đã cho tôi câu trả lời của Pavel Shved để nhận ra rằng câu hỏi có lẽ là về các biến const địa phương. Tôi đã suy nghĩ về biến toàn cầu tất cả thời gian này. –

2

Bạn không thể khởi tạo const sau khi tuyên bố trong cơ thể chức năng, nhưng bạn chỉ có thể mở một khối sau các xác nhận của bạn:

void func() 
{ 
    int y; 
    //do assertions 
    assert(something); 
    { 
     int const x = 5; 
     // function body 
    } 
} 
3

Hãy lưu ý rằng ngay cả trong C89, bạn thường có thể di chuyển định nghĩa gần hơn đến điểm sử dụng đầu tiên của giới thiệu ng một khối trần chỉ cho phạm vi bổ sung. Trước:

int a, b, c; 

a = 12; 
// do some stuff with a 

b = 17; 
// do some stuff with a and b 

c = 23; 
// do some stuff with a, b, and c 

Sau:

int a = 12; 
// do some stuff with a 
{ 
    int b = 17 
    // do some stuff with a and b 
    { 
     int c = 23; 
     // do some stuff with a, b and c 
    } 
} 

Với C99 tất nhiên, bạn có thể định nghĩa các biến khác so với lúc bắt đầu của một khối:

int a = 12; 
// do some stuff with a 

int b = 17 
// do some stuff with a and b 

int c = 23; 
// do some stuff with a, b and c 
2

sơ lược về phạm vi khối và C99 phương pháp khai khác đã cho thấy, câu trả lời là không; bạn không thể hoãn khởi tạo biến const. Dù sao, const không phải là rất hữu ích cho các biến địa phương. Thời gian chính tôi sử dụng từ khóa const trong C là:

  • Con trỏ trong đối số chức năng (hoặc biến con trỏ cục bộ dựa trên đối số) trong đó hàm đang tôn trọng hợp đồng không sửa đổi dữ liệu được trỏ đến. Từ khóa const giúp đảm bảo rằng việc thực hiện hàm tôn trọng yêu cầu không sửa đổi (nó đòi hỏi nỗ lực đặc biệt để loại bỏ const) và cho phép yêu cầu này truyền bá thông qua nhiều cuộc gọi hàm.
  • Để khai báo các bảng hằng số biên dịch (bảng tra cứu, đối tượng cố định định sẵn, v.v.) mà tôi muốn được lưu trữ trong phần chỉ đọc của tệp nhị phân để chúng không sử dụng tài nguyên vật lý bổ sung khi chạy.

Đôi khi tôi khai báo biến cục bộ const nếu tôi nghĩ nó sẽ giúp người đọc hiểu được hàm, nhưng điều đó khá hiếm.

0

Nếu bạn muốn bỏ đi const trên LHS, thì sao?

const int n = 0; 

*((int*)&n) = 23; 
+1

Làm thế nào về điều này? Ý tưởng rất tồi. Nó vượt qua các hạn chế ngôn ngữ đã quyết định đưa ra. Thậm chí có thể gây ra lỗi, tùy thuộc vào việc thực hiện trình biên dịch của bạn. – einpoklum

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