2010-11-16 25 views
9

Gần đây tôi cố gắng sử dụng /Wall Visual C++ option để cho phép tất cả các cảnh báo và phát hiện ra rằng đoạn mã sau:Làm thế nào để giải quyết cảnh báo C4191 xung quanh các cuộc gọi đến GetProcAddress với FARPROC?

typedef BOOL (WINAPI * TIsWow64ProcessFunction)(HANDLE, BOOL*); 
TIsWow64ProcessFunction isWow64ProcessFunction = reinterpret_cast<TIsWow64ProcessFunction> (
    ::GetProcAddress(kernel32DllHandle, "IsWow64Process")); 

sinh ra C4191:

warning C4191: 'reinterpret_cast' : unsafe conversion from 'FARPROC' to 'TIsWow64ProcessFunction' 
Calling this function through the result pointer may cause your program to fail 

Nếu tôi sử dụng một C-style cast cảnh báo tương tự xuất hiện nhưng bây giờ nó đề cập đến "type cast" thay vì "reinterpret_cast".

Cảnh báo tương tự được lặp lại cho mọi trường hợp tôi gọi GetProcAddress() và chuyển giá trị trả về của nó thành một số con trỏ hàm có thể sử dụng.

Làm cách nào để giải quyết các cảnh báo này? Tôi có cần thay đổi mã của mình không?

+0

#pragma warning (disable: 4191) có vẻ thích hợp nếu mục tiêu đạt 0 cảnh báo: Cảnh báo cụ thể này là vô ích khi không có (rõ ràng) cách để tránh khi giữ chức năng. –

+0

Nó có cảnh báo cho bạn không? Tôi không bao giờ sử dụng/tường, chỉ có mức cảnh báo P4 trong VS. typedef BOOL (WINAPI * DISABLEREDIR) (PVOID *); DISABLEREDIR fpnDisableRedir = NULL; fpnDisableRedir = (DISABLEREDIR) GetProcAddress (hKernel32, "Wow64DisableWow64FsRedirection"); – Kra

+1

@Kra: Vâng, nó sinh ra C4191 với/Wall. Điều quan trọng là C4191 bị vô hiệu hóa theo mặc định và/Wall cho phép nó. – sharptooth

Trả lời

6

Bạn đang truyền một hàm FARPROC (con trỏ hàm không có arg) đến một con trỏ hàm với arg. Thông thường đây là một điều cực kỳ câm để làm điều đó có thể sẽ dẫn đến sự tham nhũng ngăn xếp. Bây giờ nó chỉ ra rằng GetProcAddress() không thực sự trả về một FARPROC và bạn thực sự biết những gì bạn đang làm - nhưng trình biên dịch không biết điều đó và nó cảm thấy bắt buộc phải cảnh báo bạn.

Cách duy nhất bạn có thể tắt tiếng là sử dụng khóa #pragma hoặc trình biên dịch để tắt cảnh báo. Nó là xấu xí và lộn xộn, nhưng đó là lập trình Windows cho bạn. :-)

+0

Có phải 'dlsym' trên Linux tốt hơn không? – Mehrdad

+0

dlsym trả về một con trỏ void vì vậy tôi không nghĩ trình biên dịch sẽ đưa ra cảnh báo. Nó giả định rằng một void * là lớn như một con trỏ hàm. Tôi không biết điều đó có đúng không. Tôi không nghĩ tiêu chuẩn bảo đảm nó. –

+0

VS 2010 báo cáo đó là lỗi. #pragma không giúp giải quyết vấn đề. – null

2

Về cơ bản trình biên dịch không thể đảm bảo rằng hàm này thuộc loại thích hợp, vì vậy không an toàn để bạn gọi con trỏ kết quả. Tuy nhiên, trong một chương trình VS bạn không phải liên kết hoặc tải lên Windows .dll một cách rõ ràng, chúng sẽ được tải cho bạn và bất kỳ chức năng nào trong tiêu đề Windows luôn sẵn sàng để sử dụng.

+1

Giả sử tôi thực sự ned để tự động tải một thư viện. Tôi phải làm gì với cảnh báo? Tôi có bỏ qua nó không? Liệu cảnh báo chỉ có nghĩa là nó tùy thuộc vào tôi để đảm bảo rằng hàm thực sự có chữ ký bên phải trong việc triển khai? – sharptooth

+0

@sharptooth: Về cơ bản, có. Giải pháp duy nhất cho vấn đề này là tải tĩnh của một DLL - đó là những gì xảy ra với các tiêu đề Windows. – Puppy

+0

@Puppy - Bạn có thể truyền kết quả của 'GetprocAddress' thành' void * '. Điều đó sẽ bí mật cảnh báo C4191. Sau đó, đưa nó vào kiểu con trỏ hàm. – jww

5

Như câu trả lời khác đã đề cập, đây là một cảnh báo hữu ích. Normally, this type of coercion would be a serious bug hiding in your application.

Vì vậy, có thể bạn không muốn vô hiệu hóa nó trên toàn cầu bằng công cụ chuyển đổi trình biên dịch. Tuy nhiên, bạn vẫn cần phải gọi GetProcAddress và bạn thích các bản dựng của mình để biên dịch một cách rõ ràng mà không cần cảnh báo.

Bạn có hai lựa chọn tốt:

  1. Suppress từng cảnh báo cá nhân sử dụng một pragma MSVC cụ thể. Trong một dòng mới ngay trên dàn diễn viên bẩn, thêm đoạn mã sau:

    #pragma warning(suppress: 4191) 
    

    này sẽ bỏ qua cảnh báo cho các dòng rất cạnh mã chỉ, đảm bảo rằng nó không phải là đàn áp trên toàn cầu và bạn sẽ vẫn nhận được cảnh báo nếu bạn cố gắng làm điều gì đó ngu ngốc ở nơi khác trong cơ sở mã. Tất nhiên, bạn sẽ cần phải thêm điều này mỗi khi bạn sử dụng GetProcAddress, đó là một loại đau. Tệ hơn nữa, đó là một tiện ích mở rộng không phải MSVC dành riêng cho di động làm xấu mã của bạn.

    Vì vậy, thay thế & hellip;

  2. Bạn có thể tắt các cảnh báo bằng đúc một cách rõ ràng là kết quả của GetProcAddress (một FARPROC) để void*, và sau đó đúc mà void* để loại hàm con trỏ cụ thể. Ví dụ:

    typedef BOOL (__stdcall *TIsWow64ProcessFunction)(HANDLE, BOOL*); 
    
    TIsWow64ProcessFunction isWow64ProcessFunction = 
        reinterpret_cast<TIsWow64ProcessFunction>(
         reinterpret_cast<void*>(
         ::GetProcAddress(hInstance, "IsWow64Process"))); 
    

    Cách tiếp cận này sẽ hoạt động với các trình biên dịch khác, hơi kém xấu xí và được cho là mang ý nghĩa ngữ nghĩa hơn.

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