You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#如何正确P/Invoke调用libc库getpwnam函数获取用户UID/GID

错误原因

  • 结构体定义不符合非托管封送要求:原生passwd结构体中的字符串字段为char*指针,你直接定义为托管string类型会导致运行时把非托管指针当作托管对象访问,触发内存错误。同时未显式指定结构体布局,字段偏移可能和原生实现不匹配。
  • getpwnam的P/Invoke签名错误:原生getpwnam返回值为struct passwd*指针(指向glibc内部静态存储区),不是void,也不会把结果填充到你传入的out参数中,调用逻辑完全不符合接口约定。
  • getpwnam_r的签名错误:原生getpwnam_r返回int类型错误码,第二参数是struct passwd*缓冲区指针,最后一个参数是struct passwd**结果指针,你当前的值类型传参方式完全错误。

正确实现

你只需要获取Uid和Gid的话可以用如下简化实现,不需要处理字符串字段的封送转换:

using System;
using System.Runtime.InteropServices;

if (args.Length < 1) {
    Console.Error.WriteLine("Provide user name.");
    Environment.Exit(-1);
}

var name = args[0];

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
    var pwdPtr = Syscall.getpwnam(name);
    if (pwdPtr == IntPtr.Zero) {
        Console.WriteLine($"User {name} not found.");
        return;
    }
    var passwd = Marshal.PtrToStructure<Passwd>(pwdPtr);
    Console.WriteLine($"User = {name}, UID = {passwd.Uid}, GID = {passwd.Gid}");
}
else {
    Console.WriteLine("It supposed to be run on Linux.");
}

[StructLayout(LayoutKind.Sequential)]
public struct Passwd
{
    // 前两个字段为char*指针,占位保证Uid/Gid偏移和原生结构体匹配,不需要处理内容
    public IntPtr Name;
    public IntPtr Password;
    public uint Uid;
    public uint Gid;
    // 后续字段无需读取可省略
}

static class Syscall
{
    [DllImport("libc", SetLastError = true)]
    public static extern IntPtr getpwnam(string name);
}

如果需要多线程安全的实现,可改用getpwnam_r版本,避免静态缓冲区的重入问题。

内容的提问来源于stack exchange,提问作者Harry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 02:06:03