2008-10-04 28 views
6

Mã mẫu cho biết cách tạo chủ đề bằng cách sử dụng MFC khai báo hàm chuỗi làm cả tĩnh và __cdecl. Tại sao yêu cầu thứ hai? Chủ đề Boost không làm phiền với quy ước này, vậy nó chỉ là một lỗi thời?Tại sao các hàm chuỗi cần được khai báo là '__cdecl'?

Ví dụ (MFC):

static __cdecl UINT MyFunc(LPVOID pParam) 
{ 
... 
} 

CWinThread* pThread = AfxBeginThread(MyFunc, ...); 

Trong khi Boost:

static void func() 
{ 
... 
} 

boost::thread t; 
t.create(&func); 

(các mẫu mã có thể không chính xác 100% như tôi hư không gần một IDE).

Điểm của __cdecl là gì? Làm thế nào để nó giúp đỡ khi tạo chủ đề?

Trả lời

4

__cdecl yêu cầu trình biên dịch sử dụng quy ước gọi C (trái ngược với stdcall, fastcall hoặc bất kỳ quy ước gọi nào khác mà trình biên dịch của bạn hỗ trợ). Tôi tin rằng, VC++ sử dụng stdcall theo mặc định.

Quy ước gọi ảnh hưởng đến những thứ như cách đối số được đẩy lên ngăn xếp (hoặc thanh ghi, trong trường hợp fastcall) và người bật đối số khỏi ngăn xếp (người gọi hoặc callee).

Trong trường hợp Tăng cường. Tôi tin rằng nó sử dụng chuyên môn hóa mẫu để tìm ra loại hàm và quy ước gọi điện thích hợp.

+0

Tăng cường không xem xét gọi quy ước. Đây không phải là tính năng cấp độ ngôn ngữ (nhiều tính năng của Trình liên kết). MS sử dụng nó để tương thích ngược với mã. –

+0

Loki có câu trả lời tốt nhất – SChalice

1

Bởi vì chuỗi của bạn sẽ được gọi bởi một hàm thời gian chạy để quản lý điều này cho bạn và hàm đó hy vọng nó sẽ theo cách đó. Boost đã thiết kế nó theo một cách khác.

Đặt điểm ngắt ở đầu chức năng chuỗi của bạn và nhìn vào ngăn xếp khi được gọi, bạn sẽ thấy hàm thời gian chạy gọi cho bạn.

4

Nhìn vào nguyên mẫu cho AfxBeginThread():

CWinThread* AfxBeginThread(
    AFX_THREADPROC pfnThreadProc, 
    LPVOID pParam, 
    int nPriority = THREAD_PRIORITY_NORMAL, 
    UINT nStackSize = 0, 
    DWORD dwCreateFlags = 0, 
    LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL 
); 

AFX_THREADPROC là một typedef cho UINT(AFX_CDECL*)(LPVOID). Khi bạn chuyển một hàm tới AfxBeginThread(), nó phải khớp với nguyên mẫu đó, bao gồm quy ước gọi.

Các trang MSDN trên __cdecl__stdcall (cũng như __fastcall__thiscall) giải thích ưu và nhược điểm của từng quy ước gọi điện.

Nhà xây dựng boost::thread sử dụng mẫu để cho phép bạn chuyển con trỏ hàm hoặc đối tượng hàm có thể gọi, do đó không có giới hạn giống như MFC.

1

Trình biên dịch C/C++ theo mặc định sử dụng quy ước gọi C (đẩy đúng tham số bên phải đầu tiên trên ngăn xếp) cho phép làm việc với các hàm có số đối số biến đổi như printf.

Quy ước gọi Pascal (còn gọi là "fastcall") đẩy tham số ngoài cùng bên trái trước. Điều này là nhanh hơn mặc dù chi phí bạn khả năng của các chức năng đối số biến dễ dàng (tôi đọc một nơi nào đó họ vẫn có thể, mặc dù bạn cần phải sử dụng một số thủ thuật).

Do tốc độ phát sinh từ việc sử dụng quy ước Pascal, cả hai API Win32 và MacOS theo mặc định sử dụng quy ước gọi đó, ngoại trừ trong một số trường hợp nhất định.

Nếu chức năng đó chỉ có một tham số, trong lý thuyết sử dụng quy ước gọi là hợp pháp, mặc dù trình biên dịch có thể thực thi cùng một quy ước gọi được sử dụng để tránh mọi sự cố.

Thư viện tăng cường được thiết kế với con mắt về tính di động, do đó, chúng nên bất khả tri như quy ước người gọi mà trình biên dịch cụ thể đang sử dụng.

+0

umm fastcall đặt đối số thứ nhất trong ecx và edx. Sau đó, đẩy phần còn lại trên ngăn xếp theo thứ tự giống như phần còn lại của các quy ước gọi điện. stdcall và cdecl khác nhau trong stdcall làm sạch ngăn xếp riêng của mình, người gọi cdecl phải dọn dẹp ngăn xếp. Có cái này mà ecx == cái này – Raindog

1

Câu trả lời thực sự phải làm với cách các cửa sổ nội bộ gọi thủ tục proc luồng và mong đợi chức năng tuân theo quy ước gọi cụ thể, trong trường hợp này là macro, WINAPI, theo hệ thống của tôi được định nghĩa là:

#define WINAPI  __stdcall 

Điều này có nghĩa là chức năng được gọi có trách nhiệm làm sạch ngăn xếp. Lý do tại sao boost :: thread có thể hỗ trợ các chức năng tùy ý là nó chuyển một con trỏ tới đối tượng hàm được sử dụng trong lời gọi đến thread :: create function to CreateThread. Threadproc được liên kết với luồng chỉ đơn giản là gọi toán tử() trên đối tượng hàm.

Lý do MFC yêu cầu __cdecl do đó phải thực hiện theo cách gọi nội bộ chức năng được chuyển vào cuộc gọi đến AfxBeginThread. Không có lý do chính đáng để làm điều này trừ khi họ đang có kế hoạch cho phép các tham số vararg ...

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