簡體   English   中英

C#pInvoke在32位和64位Linux中均使用long:

[英]C# pInvoke with long in both 32 & 64 Bit Linux:

我需要調用Linux函數sysinfo

它的聲明是int sysinfo(struct sysinfo * info);

在Linux 2.3.16之前,sysinfo()用於以以下結構返回信息:

struct sysinfo {
    long uptime;             /* Seconds since boot */
    unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
    unsigned long totalram;  /* Total usable main memory size */
    unsigned long freeram;   /* Available memory size */
    unsigned long sharedram; /* Amount of shared memory */
    unsigned long bufferram; /* Memory used by buffers */
    unsigned long totalswap; /* Total swap space size */
    unsigned long freeswap;  /* swap space still available */
    unsigned short procs;    /* Number of current processes */
    char _f[22];             /* Pads structure to 64 bytes */
};

大小以字節為單位。

從Linux 2.3.23(i386),2.3.48(所有體系結構)開始,結構為:

struct sysinfo {
    long uptime;             /* Seconds since boot */
    unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
    unsigned long totalram;  /* Total usable main memory size */
    unsigned long freeram;   /* Available memory size */
    unsigned long sharedram; /* Amount of shared memory */
    unsigned long bufferram; /* Memory used by buffers */
    unsigned long totalswap; /* Total swap space size */
    unsigned long freeswap;  /* swap space still available */
    unsigned short procs;    /* Number of current processes */
    unsigned long totalhigh; /* Total high memory size */
    unsigned long freehigh;  /* Available high memory size */
    unsigned int mem_unit;   /* Memory unit size in bytes */
    char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */
};

這是我到目前為止的內容:

該功能pinvoke:

private const string DoesntFindLibC =@"/lib/x86_64-linux-gnu/libc.so.6";

[System.Runtime.InteropServices.DllImport(DoesntFindLibC)]
private static extern int sysinfo(ref sysinfo_t info);  

和結構映射:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct sysinfo_t
{
    public System.UIntPtr  uptime;             /* Seconds since boot */
    [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=3)]
    public System.UIntPtr [] loads;  /* 1, 5, and 15 minute load averages */


    public System.UIntPtr totalram;  /* Total usable main memory size */
    public System.UIntPtr  freeram;   /* Available memory size */
    public System.UIntPtr  sharedram; /* Amount of shared memory */
    public System.UIntPtr  bufferram; /* Memory used by buffers */


    // [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.
    public System.UIntPtr  totalswap; /* Total swap space size */

    public System.UIntPtr  freeswap;  /* swap space still available */
    public ushort procs;    /* Number of current processes */

    [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=22)]
    public char[] _f; /* Pads structure to 64 bytes */
}

問題在於,C代碼中的“ long”是特定於處理器體系結構的,因為在x86 32位Linux中,long的大小是32位,在x86 64位Linux中是64位,所以我必須選擇IntPtr,並且因為它是未簽名的,所以我選擇了UIntPtr。

但是,在C#/ mono中,long始終定義為Int64。

現在使用IntPtr有點不方便。 有什么我可以應用的MarshalAs屬性,或者我可以編寫一個自定義的marshaler以便我實際上可以在結構中包含ulong,但是它本地映射到IntPtr嗎? 這樣,相同的代碼就可以在x86-32和x86-64上運行。

不,您無法采取任何編組魔術來解決此問題。

但是,您可以隱藏字段並提供屬性訪問器:

using System.Runtime.InteropServices;

[StructLayoutAttribute(LayoutKind.Sequential)]
struct sysinfo_t
{
    System.UIntPtr  _uptime;             /* Seconds since boot */
    public ulong uptime {
        get { return (ulong) _uptime; }
        set { _uptime = new UIntPtr (value); }
    }

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
    System.UIntPtr [] _loads;  /* 1, 5, and 15 minute load averages */
    public ulong[] loads {
        get { return new ulong [] { (ulong) _loads [0], (ulong) _loads [1], (ulong) _loads [1]) };
        set { _loads = new UIntPtr [] { new UIntPtr (value [0]), new UIntPtr (value [1]), new UIntPtr (value [2]) }; }
    }

    // etc
}

C'long'類型很難封送,因為.NET中沒有在所有平台上都與其大小匹配的類型。 問題在於,在某些平台(Win32,Win64和Linux32)上,C'long'類型的長度可以為4個字節,而在其他平台(Linux64)上,其長度可以為8個字節。 在.NET中,不管平台如何,都有“ int”類型,它的長度為4個字節,而與平台無關,則是“ long”類型,它的長度為8個字節。 它們都不能用作C'long'類型的多平台替代方案,並且單據文檔建議使用IntPtr,因為您已經發現了,但是我發現這種方法非常不方便(在Win64上也無法使用!)。 因此,我個人更喜歡封送兩組不同的函數和結構 ,對於C'long'類型為4字節長的平台,其一組為 'int'.NET類型,對於C為'long'的平台,其另一組為'long'.NET類型。 '類型為8個字節長。 然后,我只在運行時使用if (IntPtr.Size == 8)條件來決定應使用哪個集合。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM