[DLL] Sử dụng extern “C” khi tạo DLL

Trong bài Tạo DLL đơn giản trong visual studio chúng ta đã biết tạo 1 dll đơn giản trong Visual studio. Tuy nhiên dll tạo ra chỉ có thể sử dụng được trong các project C++.

Vậy làm thế nào để tạo ra dll có thể sử dụng trong các ngôn ngữ lập trình khác ?

Để giải quyết vấn đề này khi build dll với trình biên dịch của C++ ta có 1 khái niệm là extern “C”. Trong bài viết này chúng ta cùng tìm hiểu về tác dụng của extern “C” và tại sao phải sử dụng khi tạo dll.

Name mangling

Như chúng ta đã biết trong C++ hỗ trợ function overloading là các hàm có cùng tên và khác parameters. Vì vậy khi biên dịch chương trình, trình biên dịch C++ sẽ thay đổi tên hàm bằng cách thêm thông tin về các đối số đầu vào của hàm để phân biệt các hàm overload, khái niệm đó được gọi là name mangling.

Trong C++ chuẩn không quy định tiêu chuẩn nào cho các name mangling vì vậy các trình biên dịch khác nhau có thể thêm các thông tin khác nhau vào tên hàm.

Xét ví dụ


int  f (void) { return 1; }

int  f (int)  { return 0; }

void g (void) { int i = f(), j = f(0); }

Trình biên dịch C++ có thể thêm thông tin vào tên hàm khi biên dịch như sau:


int  __f_v (void) { return 1; }

int  __f_i (int)  { return 0; }

void __g_v (void) { int i = __f_v(), j = __f_i(0); }

=> Do các hàm của C++ có thể được các trình biên dịch khác nhau, biên dịch ra các tên khác nhau nên khi xuất ra dll chúng không thể sử dụng được ở các project khác ngoài C++.

extern “C”

Với các hàm được đặt trong trong extern “C”, trình biên dịch C++ sẽ không thay đổi tên của hàm (unmangled, tùy 1 số trường hợp vẫn thay đổi theo calling conventions) khi biên dich, giống như trình biên dịch của C, ta không thể sử dụng function overloading trong đó.

Khi đó dll có thể sử dụng được trong các ngôn ngữ khác như C#, VB…

Để sử dụng chức năng này ta thêm extern “C” khi khai báo các hàm.


extern "C" DLL int Add(int a, int b);

extern "C" DLL int Sub(int a, int b);

Hoặc khai báo các hàm trong 1 block của extern “C”


#ifdef CREATE_DLL

   #define DLL _declspec(dllexport)

#else

   #define DLL _declspec(dllimport)

#endif

#ifdef __cplusplus

extern "C"

{

#endif

   DLL int Add(int a, int b);

   DLL int Sub(int a, int b);

   DLL int Mul(int a, int b);

   DLL float Div(int a, int b);

#ifdef __cplusplus

}

#endif

Tóm lại :

– Trong C++ hỗ trợ function overloading nên các hàm sau khi biên dich sẽ được thêm thông tin về parameters vào tên hàm gọi là name mangling.

–  Để dll có thể sử dụng trong các ngôn ngữ khác khi biên dịch với trình biên dịch của C++ ta phải thêm extern “C” để build các hàm đó ra C interface (unmangled).

Nếu bạn có bất cứ vấn đề gì về nội dung bài viêt vui lòng comment bên dưới để cùng nhau trao đổi.

Code ví dụ tại Github : https://github.com/deepcppofficial/DLL

Có 1 bình luận

Leave A Comment?