2010-04-13 20 views
30

Tôi đã làm việc trong C quá lâu đến mức thực tế là các trình biên dịch thường thêm dấu gạch dưới vào đầu của một extern chỉ là hiểu ... Tuy nhiên, another SO question today khiến tôi băn khoăn về lý do thực sự tại sao dấu gạch dưới được thêm vào. Một tuyên bố rằng một lý do là:Tại sao các trình biên dịch C lại thêm dấu gạch dưới vào các tên bên ngoài?

Đó là thực tế phổ biến cho trình biên dịch C để thêm vào trước một hàng đầu nhấn mạnh đến tất cả các định danh chương trình phạm vi bên ngoài để ngăn chặn đụng độ với sự đóng góp từ hỗ trợ ngôn ngữ runtime

Tôi nghĩ rằng có ít nhất là một hạt nhân của sự thật cho điều này, nhưng cũng có vẻ như không thực sự trả lời câu hỏi, vì nếu gạch dưới được thêm vào tất cả các bên ngoài, nó sẽ không giúp ích gì nhiều trong việc ngăn chặn các xung đột.

Có ai có thông tin tốt về lý do cho dấu gạch dưới hàng đầu không?

Phần bổ sung gạch dưới có lý do khiến cuộc gọi hệ thống Unix creat() không kết thúc bằng 'e' không? Tôi đã nghe nói rằng các liên kết ban đầu trên một số nền tảng có giới hạn 6 ký tự cho tên. Nếu đó là trường hợp, sau đó thêm một dấu gạch dưới vào các tên bên ngoài dường như là một ý tưởng điên rồ (bây giờ tôi chỉ có 5 ký tự để chơi với ...).

+2

Cần lưu ý rằng hành vi này không được thực hiện trên các hệ thống ELF hiện đại. Nó đã được phổ biến trong các nền tảng aout/coff, rõ ràng. –

+0

Tại sao Clang thực hiện trên OS X? làm thế nào tôi có thể tắt nó đi? – MarcusJ

Trả lời

17

Đó là thực tế phổ biến cho trình biên dịch C để thêm vào trước một hàng đầu nhấn mạnh đến tất cả các định danh chương trình phạm vi bên ngoài để ngăn chặn đụng độ với sự đóng góp từ hỗ trợ ngôn ngữ runtime

Nếu sự hỗ trợ runtime được cung cấp bởi trình biên dịch, bạn sẽ nghĩ rằng sẽ có ý nghĩa hơn khi thêm một dấu gạch dưới vào vài số nhận dạng bên ngoài trong bộ phận hỗ trợ thời gian chạy thay thế!Khi các trình biên dịch C xuất hiện lần đầu, thay thế cơ bản cho lập trình trong C trên các nền tảng đó được lập trình bằng ngôn ngữ assembly, và nó (và đôi khi vẫn là) hữu ích để liên kết các tệp đối tượng được viết bằng assembly và C. Thật vậy (IMHO) dấu gạch dưới hàng đầu được thêm vào từ định danh C bên ngoài là để tránh xung đột với số nhận dạng trong mã assembly của riêng bạn.

(Xem thêm GCC's asm label extension; và lưu ý rằng dấu gạch dưới được thêm vào trước này có thể được coi là một hình thức đơn giản của tên mangling ngôn ngữ phức tạp hơn như C++ sử dụng phức tạp hơn tên mangling, nhưng đây là nơi nó bắt đầu..)

+0

Tôi thích cái châm biếm "GCC không có khả năng lưu các biến tĩnh trong thanh ghi. Có lẽ nó sẽ được thêm vào." nhận xét trong tài liệu được liên kết. –

+0

@MichaelBurr: nó có thể không châm biếm. Trên một số hệ thống, bạn có thể đặt trước thanh ghi toàn cục làm con trỏ tới một số vùng bộ nhớ (ví dụ: 'R9' trong một số biến thể của ARM EABI cho con trỏ cơ sở tĩnh). –

3

Từ những gì tôi luôn nghe thấy là tránh đặt tên xung đột. Không phải cho các biến extern khác nhưng nhiều hơn để khi bạn sử dụng một thư viện nó hy vọng sẽ không xung đột với tên biến mã người dùng.

1

Từ Wikipedia:

Đó là thực tế phổ biến cho các trình biên dịch C để thêm vào trước một hàng đầu nhấn mạnh đến tất cả các định danh chương trình phạm vi bên ngoài để ngăn chặn đụng độ với sự đóng góp từ hỗ trợ ngôn ngữ runtime. Hơn nữa, khi trình biên dịch C/C++ cần đưa tên vào liên kết bên ngoài như một phần của quá trình dịch, những tên này thường được phân biệt với một số kết hợp của nhiều dấu gạch dưới đầu hoặc cuối.

Thực hành này sau đó được mã hóa như một phần của tiêu chuẩn ngôn ngữ C và C++, trong đó việc sử dụng dấu gạch dưới hàng đầu được dành riêng cho việc triển khai.
3

Chức năng chính không phải là điểm vào thực của một tệp thực thi. Một số tệp được liên kết tĩnh có điểm vào thực mà cuối cùng gọi chính và các tệp được liên kết tĩnh đó sở hữu vùng tên không bắt đầu bằng dấu gạch dưới. Trên hệ thống của tôi, trong/usr/lib, có gcrt1.o, crt1.o và dylib1.o trong số những thứ khác. Mỗi một trong số đó có một hàm "bắt đầu" mà không có dấu gạch dưới mà cuối cùng sẽ gọi điểm vào "_main". Mọi thứ khác ngoài các tệp đó có phạm vi bên ngoài. Lịch sử phải làm với bộ trộn và C trong một dự án, trong đó tất cả C được coi là bên ngoài.

5

nếu trình biên dịch c luôn đặt trước dấu gạch dưới trước mỗi ký hiệu, thì mã khởi động/c-runtime, (thường được viết trong assembly) có thể sử dụng nhãn và ký hiệu không bắt đầu bằng dấu gạch dưới, (chẳng hạn như ký hiệu ' khởi đầu').

ngay cả khi bạn viết hàm start() trong mã c, nó được tạo dưới dạng _start trong đầu ra đối tượng/asm. (lưu ý rằng trong trường hợp này, không có khả năng mã c để tạo ra một biểu tượng không bắt đầu bằng dấu gạch dưới) vì vậy trình coder khởi động không phải lo lắng về việc phát minh các ký hiệu không rõ ràng (như $ _dontuse42% $) cho mỗi các biến/nhãn toàn cục của anh ấy/cô ấy.

để trình liên kết không phàn nàn về xung đột tên và lập trình viên vui vẻ. :)

thông tin sau đây khác với thực hành của trình biên dịch thêm một dấu gạch dưới ở định dạng đầu ra của nó.

Thực hành này sau đó được mã hóa như một phần của tiêu chuẩn ngôn ngữ C và C++, trong đó việc sử dụng dấu gạch dưới hàng đầu được dành riêng cho việc triển khai.

đó là quy ước được tuân theo, đối với thư viện sytem c và các thành phần hệ thống khác. (và cho những thứ như __FILE__ vv).

(lưu ý rằng đó là một biểu tượng (ví dụ: _time) có thể dẫn đến 2 dấu gạch hàng đầu (__time) trong sản lượng tạo ra)

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