2013-06-11 47 views
7

Tôi đang thử một ví dụ nhỏ để biết về biến bên ngoài tĩnh và cách sử dụng nó. Biến tĩnh là phạm vi cục bộ và biến bên ngoài là phạm vi toàn cục.khai báo tĩnh của m sau khai báo không tĩnh

static5.c

#include<stdio.h> 
#include "static5.h" 
static int m = 25; 
int main(){ 
func(10); 
return 0; 
} 

static5.h

#include<stdio.h> 
int func(val){ 
extern int m; 
m = m + val; 
printf("\n value is : %d \n",m); 
} 

gcc static5.c static5.h

o/p:

static5.c:3: error: static declaration of m follows non-static declaration 
static5.h:3: note: previous declaration of m was here 

EDITED

Chương trình đúng:

a.c: 
#include<stdio.h> 
#include "a1_1.h" 
int main(){ 
func(20); 
return 0; 
} 

a1.h: 
static int i = 20; 

a1_1.h: 
#include "a1.h" 
int func(val){ 
extern int i; 
i = i + val; 
printf("\n i : %d \n",i); 
} 

này hoạt động tốt hoàn toàn tốt đẹp. Nhưng điều này được biên dịch thành một đơn vị biên dịch đơn. Do đó có thể truy cập biến tĩnh. Trên đơn vị biên dịch, chúng ta không thể sử dụng biến tĩnh bằng cách sử dụng biến ngoài.

+0

Không nên là 'extern int m;' nằm ngoài cơ quan chức năng? – Kninnug

+1

m được khai báo là tĩnh trong static5.c và do đó phạm vi nằm trong tệp.so là lỗi. –

+0

Vậy câu hỏi là gì? m là tĩnh đối với tệp static5.c, do đó không thể truy cập tệp đó ở bất kỳ nơi nào khác, thậm chí khai báo nó với 'extern' – greydet

Trả lời

13

Hãy nhớ điều này (trích dẫn Eli Bendersky):

  • Một biến tĩnh bên trong một hàm giữ giá trị của nó giữa lời gọi.
  • Một biến toàn cầu tĩnh hoặc một chức năng được "nhìn thấy" chỉ trong file nó khai báo trong

Trong code của bạn, static int m = 25; có nghĩa là phạm vi m 's được giới hạn chỉ đến tập tin đó, có nghĩa là, nó chỉ hiển thị bên trong static5.c và không có nơi nào khác.

Nếu bạn muốn sử dụng m bên ngoài static5.c, hãy đảm bảo xóa từ khóa static khỏi khai báo biến.

Đối với một lời giải thích kinh điển hơn, cùng với một ví dụ, xem this answer by Eli Bendersky

EDIT: (theo khuyến nghị Klas') ** Phạm vi thực tế là một đơn vị biên soạn, không phải là tập tin nguồn. Đơn vị biên dịch là cách tệp trông sau bước tiền xử lý

+3

Phạm vi là đơn vị biên dịch chứ không phải tệp nguồn. Đơn vị biên dịch là cách tệp trông sau bước tiền xử lý, và sau đó func nằm trong cùng một tệp. –

+0

@ KlasLindbäck Cảm ơn bạn đã nhận xét! Tôi sẽ cập nhật câu trả lời của tôi. – NlightNFotis

+0

@NlightNFortis: Chỉ một đơn vị biên dịch của nó. Tôi làm gcc static5.c và static5.h. mã được biên dịch thành đơn vị biên dịch đơn. Nhưng tôi vẫn gặp lỗi. – Angus

2

xóa từ khóa tĩnh trong khi khai báo m và các lỗi sẽ bị xóa và bạn sẽ có thể nhận câu trả lời là 50. Từ khóa tĩnh tạo phạm vi để hạn chế trong tệp.

3

Vấn đề chính xác như được nêu trong thông báo lỗi. m được khai báo là int bình thường nhưng sau đó được xác định là static int.

extern yêu cầu trình biên dịch/trình liên kết tìm biến trong bảng toàn cầu của các biến.

static (bên ngoài functon) yêu cầu trình biên dịch loại trừ biến khỏi bảng toàn cầu của các biến.

Bạn có thấy xung đột không?

Để khắc phục sự cố, hãy xóa từ khóa static khỏi định nghĩa hoặc di chuyển định nghĩa trên bao gồm static5.h.

Cần lưu ý rằng cách bạn đã thiết kế tệp của mình không được coi là phương pháp hay nhất. Bao gồm các tệp thường không chứa các hàm.

+0

Tôi cũng nghĩ như vậy lúc đầu, nhưng tiêu chuẩn thì linh hoạt hơn. Nếu khai báo 'static' xuất hiện trước khai báo' extern', nó hoàn toàn ổn. Xem câu trả lời của tôi để tham khảo. Chỉ có vấn đề là nếu khai báo 'extern' đến trước. – Shahbaz

+0

@Shahbaz Cảm ơn bạn đã làm rõ. Tôi đã không chắc chắn liệu các tuyên bố extern sẽ là sai lầm của chỉ đơn giản là thừa. –

14

static có một logic rất đơn giản. Nếu biến là static, điều đó có nghĩa là biến đó là biến toàn cầu, nhưng phạm vi của nó bị giới hạn ở nơi biến được xác định (nghĩa là chỉ hiển thị ở đó). Ví dụ:

  • Bên ngoài một chức năng: biến toàn cầu nhưng chỉ hiển thị trong file (trên thực tế, các đơn vị biên soạn)
  • Bên trong một chức năng: biến toàn cầu nhưng chỉ hiển thị trong các chức năng
  • (C++) Bên trong một lớp học: biến toàn cầu nhưng chỉ hiển thị cho lớp

Bây giờ chúng ta hãy xem những gì các tiêu chuẩn C11 nói về staticextern (tôi nhấn mạnh):

6.2.2.3

Nếu khai báo định danh phạm vi tệp cho một đối tượng hoặc hàm chứa thông số lớp lưu trữ static, số nhận dạng có liên kết nội bộ.

6.2.2.4

Đối với một định tuyên bố với việc lưu trữ-lớp specifier extern trong một phạm vi trong đó một tuyên bố trước đó của nhận dạng đó là có thể nhìn thấy, nếu việc khai báo trước khi xác định mối liên kết nội bộ hay bên ngoài, các mối liên kết của số nhận dạng tại khai báo sau cũng giống như liên kết được chỉ định tại khai báo trước. Nếu không có khai báo trước, hoặc nếu khai báo trước chỉ định không có liên kết, thì số nhận dạng có liên kết bên ngoài.

6.2.2.7

Nếu, trong một đơn vị dịch thuật, nhận dạng tương tự xuất hiện với cả hai liên kết nội bộ và bên ngoài, hành vi này là không xác định.

Vì vậy, tiêu chuẩn đầu tiên nói rằng, nếu bạn có:

static int m; 
extern int m; 

sau đó tuyên bố thứ hai (với extern) sẽ coi là người đầu tiên và cuối cùng m vẫn sẽ static.

Tuy nhiên, trong bất kỳ trường hợp nào khác, nếu có khai báo với cả liên kết nội bộ và bên ngoài, hành vi không xác định. Điều này thực sự khiến chúng tôi chỉ có một lựa chọn:

extern int m; 
static int m; 

ví dụ: extern khai trước static khai. gcc đủ tốt để báo lỗi cho bạn trong trường hợp này là hành vi không xác định.

+0

Xin chào, cảm ơn lời giải thích tốt đẹp. Nhưng nó ngăn cản tôi rằng người ta sẽ sử dụng 'static' và' extern' cùng nhau - dường như nói với tôi "Tôi muốn var a chỉ liên kết với tệp này (tĩnh) và tôi sẽ phơi bày nó (extern) với tất cả các tệp khác" . Nghe có vẻ mâu thuẫn. Tôi có đúng với hiểu biết của mình không? Nếu không, khi nào thì sẽ cần sử dụng cả 'static' và' extern' cùng nhau? Cảm ơn trước. – Unheilig

+0

@unheilig, đúng trong dự án cá nhân của bạn, nhưng nó không phải không có công đức nói chung. Trong trường hợp 'static' trước' extern', hãy tưởng tượng một thư viện với các tệp tiêu đề thông thường với các khai báo hàm extern. Bạn có thể ghi đè lên một số hàm đó bằng cách khai báo chúng là 'tĩnh' trước khi bao gồm tiêu đề. Ví dụ, một loại 'valgrind' được biên dịch có thể được thực hiện với phương thức này. – Shahbaz

+0

Cách khác có thể là vấn đề bởi vì sau khai báo 'extern', trình biên dịch sẽ tạo mã được liên kết với khai báo đó, nhưng sau đó bạn nói nó được coi là' tĩnh', do đó trình biên dịch phải quay lại và sửa chữa mã trước. Vì trình biên dịch C là một lần, điều này gây phiền toái nhất. – Shahbaz

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