2012-06-29 35 views
6

Như tôi biết, quy ước gọi là trình biên dịch và phụ thuộc vào kiến ​​trúc. Nhưng có bất kỳ sự khác biệt rõ ràng giữa C và C + + gọi quy ước?Sự khác biệt giữa các quy ước gọi C và C++ là gì?

+0

Vui lòng kiểm tra này đầu tiên: [Stackoverflow] [1] [1]: http://stackoverflow.com/questions/949862/what-are-the-different-calling-conventions-in- cc-and-what-do-each-mean – Saif

+0

@Saif Có tôi đã thấy điều đó trước đây. Nhưng câu hỏi đó là về các quy ước gọi trong trình biên dịch C/C++. Không phải về sự khác biệt giữa quy ước gọi C và quy ước gọi C++. Dù sao cảm ơn – Kadiam

Trả lời

9

Nhưng có bất kỳ sự khác biệt rõ ràng nào giữa quy ước gọi điện C và C++ không?

Nói chung, không có. C++ được thiết kế cố ý để có thể tương thích với C, và đặc biệt nó sử dụng giao diện nhị phân ứng dụng C trên tất cả các hệ thống.

Nhưng C ABI không phục vụ nhiều tính năng mà C++ cần (cụ thể là quá tải, không gian tên và mẫu chức năng) để trình biên dịch C++ thực hiện một số thay đổi đối với tên hàm. Điều này được gọi là name mangling

Vì vậy, để các cuộc gọi chức năng giữa mã C và C++ hoạt động, các chức năng này phải được khai báo là extern "C" để vô hiệu hóa tên mangling và đảm bảo rằng các quy ước gọi là những dự kiến ​​của C (nhưng tôi mong rằng khía cạnh thứ hai này tự động xuất hiện, mặc dù tiêu chuẩn không ủy quyền điều này).

C++ cũng có thêm ước gọi cho các chức năng thành viên (đôi khi được gọi thiscall) mà không tồn tại trong C. Nhưng chức năng miễn phí sử dụng quy ước gọi điện thoại giống như C, tùy theo đó là trên một hệ thống nhất định.

+4

Tôi đã không nhìn thấy bất cứ điều gì bất cứ nơi nào mà đảm bảo bất cứ điều gì nói ở đây. Quy ước gọi duy nhất trong C++ giống với C là các hàm được khai báo là extern "C". Nhưng tôi đã được biết là sai trước đây. Nếu bạn có một tham chiếu nó sẽ là tuyệt vời. –

+2

@LokiAstari Có một số cuốn sách của Bjarne Stroustrup mà tất cả đều nói chính xác điều đó. – EJP

+0

Trong khi C++ được thiết kế để có thể tái sử dụng quy ước gọi C cho những gì được chia sẻ, cách duy nhất để chắc chắn là sử dụng extern "C" và tôi sẽ ngạc nhiên nếu không có trình biên dịch nào tận dụng ưu thế thông tin chi tiết để khắc phục sự cố với một quy ước gọi điện C trước đó. – AProgrammer

2

Toàn bộ khái niệm về các quy ước gọi điện khác nhau giữa các ngôn ngữ vượt quá bất kỳ ngôn ngữ cụ thể nào (và thông số của ngôn ngữ). Và đó là cách nó nên được, những thứ như vậy là không có mối quan tâm đến các đặc điểm kỹ thuật của bất kỳ ngôn ngữ đó là giá trị tên của nó. Về cơ bản, bạn nói đúng, nó nằm trong miền thực hiện cụ thể của một đặc tả - của kiến ​​trúc trình biên dịch. Chắc chắn, một số khái niệm được thảo luận trong đặc tả/tiêu chuẩn của một ngôn ngữ cụ thể như đặc tả liên kết có thể ảnh hưởng đến quy ước gọi điện, nhưng nó không phải là kết quả được lên kế hoạch.

nhiệm vụ ABI là để chuẩn hóa/chính thức hóa các khái niệm như vậy mà, sau đó một lần nữa, mọi người không có nghĩa vụ tôn trọng (và rất có thể vì bảng đầy màu sắc của hiện thực khác nhau khá một chút)

Thực sự, các đặc điểm kỹ thuật cần phải được lãng quên các tham số được truyền vào như thế nào, có thể kết thúc trên stack hay các thanh ghi, sự kết hợp cả hai, thứ tự phân bổ vv. Đó là công việc của những kẻ làm việc trên thực hiện và những người thiết kế phần cứng thực tế, quan trọng hơn là hướng dẫn bộ.

Do đó: Không phải C, cũng như C++, như được chuẩn hóa có bất kỳ lời nói nào về cách thức công cụ được triển khai. Do đó, không có sự khác biệt vốn có với ngôn ngữ. Chỉ theo cách chúng được áp dụng. Và đó là lĩnh vực của kiến ​​trúc trình biên dịch.

+0

thanks @Domagoj Nhưng còn tên mangling thì sao? Có tên mangling một sự khác biệt giữa C a C + + gọi quy ước? – Kadiam

+0

@Kasnel Nó có nguồn gốc từ C, tốt, một phần (đã có rất nhiều thời gian để phát triển, vì vậy trình độ chuyên môn cần phải được sử dụng). Nó cũng được chuẩn hóa - bởi giao diện nhị phân ứng dụng. Và về cơ bản không có sự khác biệt. Thông thường nó thay đổi khi trình biên dịch cần phải giới thiệu công cụ mới, mangling tên đã được khoảng một thời gian rất dài và không cần phải sửa chữa những gì không bị hỏng. –

4

Như tôi biết, quy ước gọi là phụ thuộc vào trình biên dịch và kiến ​​trúc.

Có.

Nhưng có bất kỳ sự khác biệt rõ ràng nào giữa quy ước gọi điện C và C++ không?

Câu hỏi hay hơn là "Có điểm tương đồng nào không?"

Có:

Một chức năng tuyên bố extern "C" bên trong một ứng dụng C++ có quy ước gọi cùng được sử dụng bởi một hàm C trên kiến ​​trúc mà

Bất kỳ giả định khác bạn thực hiện về kêu gọi công ước là đầu cơ và có thể xảy ra.

5

Không có gì trong cả hai tiêu chuẩn yêu cầu các quy ước gọi C và C++ phải giống nhau trên một trình biên dịch đã cho, khác với C++ hàm được khai báo extern "C" n phải được gọi một cách thông minh với cùng quy ước gọi là hàm C.

Đó là lý do tại sao một con trỏ trỏ đến chức năng và liên kết con trỏ tới hàm-với-C với cùng các tham số và kiểu trả về, có các loại khác nhau. Khi hàm được gọi, trình biên dịch có thể biết từ kiểu gọi quy ước để gọi nó với, nếu chúng khác nhau.

Trong thực tế, tôi không nghĩ mình đã từng xử lý một ví dụ sử dụng quy ước gọi không tương thích giữa các chức năng miễn phí có và không có liên kết C. Thông thường, việc thực hiện C++ thông qua quy ước gọi của nó từ ABI của hệ thống mà nó đang lập kế hoạch để chạy, để tạo ra các đối tượng có thể liên kết (thực thi và thư viện) mà người dùng khác của hệ thống có thể hiểu được về ABI.

Điều này là không bắt buộc - tiêu chuẩn không quan tâm có hay không có hệ thống ABI và hệ thống thường không quan tâm đến cách thực hiện cuộc gọi trong một tệp thực thi khép kín [*]. Nó chỉ là hợp lý để làm điều đó, trừ khi có một số lý do phi thường không. Hệ thống ABI trên một hệ thống cụ thể có thể hoặc không đề cập đến C++ - nếu không thì việc thực thi C++ là của riêng nó, như các hàm không liên kết C có liên quan, nhưng như tôi nói nó là hợp lý để thực hiện các hàm có thể có liên kết C sử dụng cùng một quy ước gọi như thể chúng có liên kết C.

Tôi nói "không tương thích" thay vì "khác", vì tất nhiên có một số thứ không được đề cập trong quy ước gọi C nhưng cần phải được chỉ định trong quy ước gọi C++. Làm thế nào để vượt qua một con trỏ-to-thành viên-chức năng, ví dụ. Có thể đây là không phải được hệ thống ABI ghim xuống, và do đó còn lại để triển khai C++. Lý do cho việc này là để lại việc thực hiện hàm con trỏ tới thành viên lên đến thực thi C++, thay vì hệ thống ABI làm điều gì đó mà nhà sản xuất coi là công việc của một trình biên dịch C++.

Với quy ước gọi ngoài đường, lưu ý rằng mangling tên không thể tránh khỏi là khác nhau giữa một chức năng miễn phí có hoặc không có liên kết C. Lý do là C++ mangling tên phải bao gồm các loại tham số (vì quá tải hàm), trong khi C mangling tên phải không (vì khai báo hàm extern với các tham số không xác định).

[*] Mặc dù tôi đã nhìn thấy các ví dụ khi sử dụng quy ước gọi điện "sai" sẽ làm hỏng mọi thứ. ISTR một thiết bị di động Windows nơi bạn định dạng ngăn xếp khác với hệ điều hành mong đợi, sau đó một số trường hợp ngoại lệ phần cứng sẽ loại bỏ thiết bị vì hệ điều hành đã cố gắng truy xuất ngăn xếp của chuỗi vi phạm và không thể. Vì vậy, ít nhất là trên phiên bản hệ điều hành, có lẽ khoảng năm 2005, nếu bạn muốn chẩn đoán của hệ điều hành để làm việc thì bạn phải sử dụng các quy ước gọi điện của Windows trong nội bộ. Hoặc dù sao là một phần của quy ước gọi điện có liên quan đến định dạng khung ngăn xếp. Dĩ nhiên, điều này hoàn toàn là lỗi của chúng tôi, nhưng tôi không biết liệu chúng tôi có thể sửa chữa nó đúng cách hay không bằng cách cài đặt các trình xử lý riêng của chúng tôi cho các ngoại lệ phần cứng, thay vì làm việc xung quanh chúng bằng cách không gây ra ngoại lệ ngay từ đầu.Nó có nghĩa là một quá trình người dùng chế độ có thể trivially đi hệ điều hành xuống với một ngăn xếp tràn, mặc dù, và cũng có thể là khó khăn hơn để gỡ lỗi mã của chúng tôi hơn trên các cửa sổ khác. Vì vậy, chúng tôi hơi đổ lỗi cho hệ điều hành.

1

Không có tiêu chuẩn C hoặc C++ nào xác định ABI. Đây là một quyết định thiết kế có chủ ý cho phép các nhà văn biên dịch tự do tạo ra một cách thực hiện hiệu quả nhất có thể.

Theo thời gian, quy ước gọi điện C được gọi là cdecl đã trở thành tiêu chuẩn thực tế trên kiến ​​trúc x86. Có một sự kiện tương tự là standards cho mã C chạy trên các máy AMD64, nhưng chúng khác nhau giữa các hệ điều hành UNIX và Windows.

Trên các máy Unix có một số chuyển động hướng tới một C++ ABI chung dựa trên Itanium C++ ABI do Intel phát hành. Tuy nhiên, do sự phức tạp thêm của C++, khác nhau versions của cùng một trình biên dịch và thậm chí different compiler switches thường sản xuất mã máy phù hợp với ABI không tương thích.

Sử dụng extern "C" { ... } thường có thể được dựa vào để buộc trình biên dịch thực hiện chức năng bằng cách sử dụng thực tế C ABI, nhưng ngay cả điều này không bắt buộc theo tiêu chuẩn C++.

Nếu bạn quan tâm đến mô tả toàn diện về C++ ABI hiện tại, thì bạn nên xem Agner Fog's "Calling conventions for different C++ compilers and operating systems".

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