Tại sao C cho phép nhiều khai báo toàn cầu của cùng một biến nhưng KHÔNG nhiều khai báo cục bộ?


8

Tôi nhận thấy rằng nếu tôi khai báo một biến toàn cục nhiều lần thì trình biên dịch thậm chí không đưa ra cảnh báo.

Tuy nhiên, nếu tôi khai báo một biến cục bộ trong một hàm nhiều lần, chẳng hạn, trình biên dịch gcc sẽ xuất ra lỗi và không biên dịch tệp. (Tôi hỏi về gcc, nhưng đây là câu hỏi thiết kế ngôn ngữ chung hơn, không phải là câu hỏi về gcc, vì tôi nghĩ có khả năng các trình biên dịch khác hoạt động tương tự).

Giải thích cho hành vi này là gì?


Chỉ cần chắc chắn, biến toàn cầu của bạn, luôn luôn có cùng loại phải không?
Walfrat

@Walfrat Có biến luôn được khai báo cùng loại. Nếu hai biến có cùng tên nhưng với loại khác nhau được khai báo trên toàn cầu thì gcc xuất ra lỗi "các loại xung đột cho một (biến)"
yoyo_fun

3
Bạn không thể khai báo một biến cục bộ dù chỉ một lần. Tất cả những gì bạn có thể làm là xác định nó. Khai báo một biến là nói cho trình biên dịch biết nó là gì. Xác định một biến là yêu cầu trình biên dịch phân bổ bộ nhớ cho nó. Bạn phải xác định tất cả các biến. Trong C, một định nghĩa của biến toàn cục có thể được sử dụng để khai báo nhiều lần. Nhưng nếu chương trình chỉ có extern int x;, đó là một khai báo, trình biên dịch sẽ hủy bỏ vì không có nơi nào bộ nhớ được phân bổ cho biến.
Shawnhcorey

Câu trả lời:


11

Theo hướng dẫn mã hóa :

Trong tập hợp các đơn vị dịch thuật và thư viện cấu thành toàn bộ chương trình, mỗi khai báo của một mã định danh cụ thể có liên kết bên ngoài biểu thị cùng một đối tượng hoặc chức năng. Trong một đơn vị dịch thuật, mỗi khai báo của một định danh có liên kết bên trong biểu thị cùng một đối tượng hoặc chức năng. Mỗi tuyên bố của một định danh không có liên kết biểu thị một thực thể duy nhất.

Biến cục bộ không có liên kết. vì vậy có một tên Va chạm xảy ra. Vì vậy, nhiều khai báo biến cục bộ là không thể.

Các biến toàn cầu có liên kết bên ngoài. Vì vậy, nhiều khai báo các biến toàn cục là có thể.


7
Câu trả lời này là tốt, tuy nhiên, câu hỏi tiếp theo rõ ràng là: lý do đằng sau định nghĩa này là gì?
Doc Brown

Với nhiều quirks C, lý do là "trình biên dịch C chuẩn trước đã làm theo cách này". Nếu bạn nhìn vào sự phức tạp của "định nghĩa dự kiến", rất có thể đây là trường hợp ở đây.
Sebastian Redl

9

@msc giới thiệu tốt về các quy tắc đằng sau hành vi này.

Tôi nhận thấy rằng nếu tôi khai báo một biến toàn cục nhiều lần thì trình biên dịch thậm chí không đưa ra cảnh báo.

C có ba loại khai báo toàn cầu cho các đối tượng, cụ thể là các khai báo (và tôi đang trình bày staticở đây):

  1. khai báo không phải là định nghĩa - extern int a;
  2. khai báo cũng là định nghĩa - int a = 3;hoặcextern int a = 3;
  3. định nghĩa dự kiến ​​- int a;

Nhiều khai báo loại 1 & 3 được cho phép, trong khi tối đa một định nghĩa (loại 2) được cho phép.


Giải thích cho hành vi này là gì?

Nếu bạn cũng đang hỏi về động lực cho các quy tắc này, thì đó là hỗ trợ cho việc biên dịch riêng . (Xem đơn vị dịch thuật ).

Để chia một chương trình thành nhiều tệp được biên dịch riêng biệt, chúng tôi cần một vài tính năng, cụ thể là (a) có thể khai báo mà không nhất thiết phải xác định và (b) khai báo chuyển tiếp .

Trong một đơn vị dịch thuật, chúng tôi cần có thể tham khảo các chức năng và dữ liệu toàn cầu trong một đơn vị dịch thuật khác. Và chúng tôi cũng muốn một số kiểm tra lỗi, ở đây, để khám phá các định nghĩa bị thiếu và các định nghĩa trùng lặp sai.

Đôi khi, trong cùng một đơn vị dịch thuật, chúng tôi khai báo toàn cầu và sau đó xác định nó sau. Điều này có thể xảy ra nếu chúng ta cần một tuyên bố chuyển tiếp vì một số lý do hoặc nếu chúng ta sử dụng tệp tiêu đề chung (cung cấp khai báo) trong một đơn vị dịch thuật cũng cung cấp các định nghĩa rõ ràng.

Do việc biên dịch riêng biệt trong C áp dụng bằng cách liên kết các chức năng và dữ liệu toàn cầu với nhau, các tính năng này được yêu cầu ở cấp toàn cầu nhưng không phải ở cấp địa phương.

Như @msc chỉ ra, không có điều này là cần thiết cho các biến cục bộ vì chúng không có liên kết.

C (giống như nhiều ngôn ngữ khác) không cung cấp liên kết cho các biến cục bộ vì ngôn ngữ không cố gắng hỗ trợ một hàm duy nhất bao gồm nhiều đơn vị dịch riêng biệt.

(Tất nhiên, bạn có thể có một hàm trải rộng nhiều tệp nguồn, nhưng không có nhiều đơn vị dịch.)

Một định nghĩa dự kiến ​​hoạt động giống như một tuyên bố ở chỗ nó được phép trong nhiều đơn vị dịch thuật (và cũng kết hợp độc đáo với các khai báo khác). Tuy nhiên, nếu không có định nghĩa (không dự kiến) cho mã định danh trong toàn bộ chương trình, thì tập hợp (một hoặc nhiều) định nghĩa dự kiến ​​trên nhiều đơn vị dịch (đối với một định danh) được lấy làm định nghĩa cho đối tượng có trình khởi tạo số không.

Điều này có thể được thực hiện bằng cách đưa chúng vào Phần .BSS với kích thước và căn chỉnh phù hợp; trình liên kết sẽ khớp chúng với định nghĩa thực nếu được tìm thấy, hoặc nếu không thì khớp chúng với nhau, tạo cho chúng khoảng trống trong BSS.


Khái niệm biên dịch riêng biệt có thể được hỗ trợ hoàn toàn mà không có tính năng của các định nghĩa dự kiến ​​- Tôi nghĩ rằng các định nghĩa dự kiến ​​chủ yếu là vì lý do lịch sử. (Tôi không nói rằng chúng không hữu ích, chỉ cần ngôn ngữ được tạo ra ngày hôm nay, điều này có thể được xem là không cần thiết và do đó không được cung cấp.)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.