2017-12-28 34 views
3

私は「高レベル言語」(Nim)でプログラミングしています。パフォーマンス上の理由から「C言語に移行する」必要があります。私はこのような何かをしたいと思います:特定のOSバージョンでのみ利用可能なC関数をどのように呼び出すのですか?

/* Pseudocode */ 
include <VersionHelpers.h> 
/* ...*/ 
if (isWindows8OrGreater()) { 
    /** use InterlockedIncrementNoFence64() */ 
} else { 
    /** use InterlockedIncrement64() ;(*/ 
} 

しかし、私は、私は)(InterlockedIncrementNoFence64を参照している場合、それが利用可能でなければならないので、私はそれを呼び出すようにしようとしていない場合でも、それは、Windows 7でクラッシュしていましたと言われました。

私はマルチスレッドアプリケーションを作成しており、通信は「メッセージ」(同じスレッド内であっても)で実装されています。これはすべてのメッセージに対して呼び出されるため、メモリフェンスはパフォーマンスに大きな影響を与えます。

私がその仕事のようなもの、これはC.

+2

関数を使用してランタイムではないプリプロセッサマクロを使用して、コンパイル時に関連するチェックを行います。 – alk

+0

解決策は、ターゲットOSに基づいて異なるバージョン*をビルドすることですか?それが正しい方法であれば、答えとして投稿してみませんか? –

+1

[遅延ロードDLLのリンカサポート](https://msdn.microsoft.com/en-us/library/151kt790.aspx)を使用してください。異なるバージョンをビルドする必要はなく、リンク時にインポートを解決できない場合は、処理する必要があります。Linuxの開発者がWindowsでのリンクについての解決策を提案したときは、常に懐疑的である。それらは一般的に間違っています(この場合)。 – IInspectable

答えて

2

にどのように行われるかIDKの具体的な場合にはInterlockedIncrementNoFence64は、任意のDLLからインポートされたが、ほとんどのプラットフォームに固有のコンパイラを使用して実装されていないのJavaに慣れている(x86 - 経由_InterlockedCompareExchange64,amd64 - _InterlockedIncrement64,アーム/ arm64 - _InterlockedIncrement64_nf)。したがって、この具体的な呼び出しのコードはWindows版(win7ではもちろん)で動作します。

もっと一般的なケースでは、すべてのOSでエクスポートされないいくつかの関数を使用する必要がある場合、関数ポインタとして宣言して実行時に解決できます。

HMODULE (WINAPI * LoadPackagedLibraryAddr)(
            _In_  LPCWSTR lpwLibFileName, 
            _Reserved_ DWORD Reserved 
            ); 

、ランタイムで解決それを::

*(void**)&LoadPackagedLibraryAddr = GetProcAddress(
    GetModuleHandleW(L"kernel32"), "LoadPackagedLibrary"); 

と使用:

if (LoadPackagedLibraryAddr) 
{ 
    LoadPackagedLibraryAddr(L"***",0); 
} 
else {...} 

別の可能な方法、たとえば、我々は関数ポインタを宣言することができますLoadPackagedLibrary API

てみましょう__declspec(dllimport)で宣言された関数の場合(ほとんどのWindows APIはこのプレフィックスは)次の構文を使用:

extern "C" { 
    PVOID __imp_LoadPackagedLibrary; 
} 

#ifdef _M_IX86 
__pragma(comment(linker, "/alternatename:[email protected]=___imp_LoadPackagedLibrary")) 
#endif 

__imp_LoadPackagedLibrary = GetProcAddress(
    GetModuleHandleW(L"kernel32"), "LoadPackagedLibrary"); 

#pragma warning(disable : 4551) 
if (LoadPackagedLibrary)//if (__imp_LoadPackagedLibrary) 
{ 
    LoadPackagedLibrary(L"***",0); 
} 

しかし両方の方法は、絶対同じバイナリコードを生成する、唯一異なる構文を使用します。

注:クエリウィンドウのバージョンは必要ありません。単純にAPIへのポインタを取得する必要があります。またはそれを入手して使用するか、または使用できません。

との双方向 __declspec(selectany)または #pragma comment(linker, "/alternatename:_pWeakValue=_pDefaultWeakValue")

これで我々は(すべてのWindowsのバージョン用の共通となります結果)リンク時でシンボルを解決、私たちは実際に実行時にシンボルを解決する必要があるため、ここでは動作しないだろう - 時間

関連する問題