【问题标题】:How to get the username in C/C++ in Linux?如何在 Linux 中获取 C/C++ 中的用户名?
【发布时间】:2012-01-21 13:39:59
【问题描述】:

如何在程序中不使用环境 (getenv, ...) 的情况下获取实际的“用户名”?环境是带有 Linux 的 C/C++。

【问题讨论】:

  • c和c++函数有什么区别?你是说类方法吗??
  • 所有 POSIX API 都定义为 C 函数,在 C++ 中完全可以调用。我不明白你的限制。
  • 这个限制没有任何意义...如果您需要与一个 POSIX 操作系统进行交互,那么您必须开始使用 C(或汇编)。以及如何定义“C++ 函数”? C++ 标准库没有为此提供任何东西,即使它提供了它也只是 getlogin_r 的包装器。
  • @Armed9Gagger:我很确定他的意思不是你说的,因为这没有任何意义......你能告诉我们他在作业中写的确切的话吗?可能他只是不让你写一个 C 风格的函数(使用 char * & co.),而是为 getlogin_r 编写一个 C++ 包装器(使用 std::string,...)。
  • @Armed9Gagger:技术上是cstdlib & co。是 C++ 包含(在 std 命名空间内提供旧版 C 库)。尽管如此,POSIX 标头并未包含在标准 C 中,它们是旨在用于多种语言(主要是 C 和 C++)的操作系统 API。

标签: c++ c linux posix


【解决方案1】:

unistd.h 中定义的函数getlogin_r() 返回用户名。请参阅man getlogin_r 了解更多信息。

它的签名是:

int getlogin_r(char *buf, size_t bufsize);

不用说,这个函数可以很容易地在 C 或 C++ 中调用。

【讨论】:

  • @Armed9Gagger,C++ 库中没有用于 POSIX 中定义的这些东西的 API。 C++应该使用 POSIX 函数。
  • 注意 getlogin_r 返回登录到进程控制终端的用户名。这可能与运行作业的用户不同。如果您未连接到控制终端(例如,当进程被守护进程),此功能也会失败。
  • getlogin() 这个比较简单
  • 这需要 TTY 存在 - 如果您通过某种调度程序调度您的应用程序,这可能会失败。请参阅 Nemanja Boric 的答案以获得更“强大”的版本
【解决方案2】:

来自http://www.unix.com/programming/21041-getting-username-c-program-unix.html

/* whoami.c */
#define _PROGRAM_NAME "whoami"
#include <stdlib.h>
#include <pwd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
  register struct passwd *pw;
  register uid_t uid;
  int c;

  uid = geteuid ();
  pw = getpwuid (uid);
  if (pw)
    {
      puts (pw->pw_name);
      exit (EXIT_SUCCESS);
    }
  fprintf (stderr,"%s: cannot find username for UID %u\n",
       _PROGRAM_NAME, (unsigned) uid);
  exit (EXIT_FAILURE);

}

只取主线,封装在类中:

class Env{
    public:
    static std::string getUserName()
    {
        uid_t uid = geteuid ();
        struct passwd *pw = getpwuid (uid);
        if (pw)
        {
            return std::string(pw->pw_name);
        }
        return {};
    }
};

仅适用于 C:

const char *getUserName()
{
  uid_t uid = geteuid();
  struct passwd *pw = getpwuid(uid);
  if (pw)
  {
    return pw->pw_name;
  }

  return "";
}

【讨论】:

  • 您可能无法使用 C 标准库,而不是所有 C 函数。您需要直接或间接使用 C 函数来执行您的任务。
  • 学究起来,你的程序不是缺少 endpwent() 调用吗?
  • @NemanjaBoric 不能直接用 argv[0] 获取程序名,即使编译后改了?
  • @TheXGood 啊,你的意思是_PROGRAM_NAME。是的,可以,这只是我粘贴的链接中的示例。
  • @Dr.PersonPersonII “你的程序是不是缺少 endpwent() 调用” - 这是在一次或多次调用 getpwent() 后使用的,当前和早期版本的回复没有'不使用 AFAICT,所以不。
【解决方案3】:
#include <iostream>
#include <unistd.h>
int main()
{
    std::string Username = getlogin();
    std::cout << Username << std::endl;
    return 0 ;
}

另一种方式是这样 -

#include <iostream>
using namespace std;
int main()
{
       cout << system("whoami");
}

【讨论】:

    【解决方案4】:

    使用在stdio.h 中找到的char *cuserid(char *s)

    #include <stdio.h>
    
    #define MAX_USERID_LENGTH 32
    
    int main()
    {
      char username[MAX_USERID_LENGTH];
      cuserid(username);
      printf("%s\n", username);
      return 0;
    }
    

    查看详情:

    1. https://pubs.opengroup.org/onlinepubs/007908799/xsh/cuserid.html
    2. https://serverfault.com/questions/294121/what-is-the-maximum-username-length-on-current-gnu-linux-systems

    【讨论】:

    【解决方案5】:

    通过现代 c++ 规范工作一点

    static auto whoAmI = [](){ struct passwd *tmp = getpwuid (geteuid ());
      return tmp ? tmp->pw_name : "onlyGodKnows"; 
    }
    

    【讨论】:

    • 为什么这应该是一个 lambda 而不是一个普通的函数/类?
    • 在我编写代码的上下文中,本地函数是适当的隐藏。恕我直言,如果不需要其他任何东西,可以通过函数(如您的建议)/lambdas 来避免(除其他外)它只不过是编译器已经构建的可执行对象。
    【解决方案6】:

    今天我不得不做同样的事情,但不喜欢包含任何操作系统特定的标题。因此,您可以通过跨平台方式执行以下操作,而无需求助于任何 Linux/Windows 特定标头:

    #include <stdio.h> 
    #include <memory>
    #include <stdexcept>
    #include <array>
    #include <regex>
    
    std::string execute_command(std::string cmd) 
    {
        std::array<char, 128> buffer;
        std::string result;
        
        #if defined(_WIN32)
            #define POPEN _popen
            #define PCLOSE _pclose
        #elif defined(unix) || defined(__unix__) || defined(__unix)
            #define POPEN popen
            #define PCLOSE pclose
        #endif
    
        std::unique_ptr<FILE, decltype(&PCLOSE)> pipe(POPEN(cmd.c_str(), "r"), PCLOSE);
        if (!pipe) 
        {
            throw std::runtime_error("popen() failed!");
        }
        while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) 
        {
            result += buffer.data();
        }
        return result;
    }
    std::string get_current_username()
    {
        #if defined(_WIN32)
            // whoami works on windows as well but it returns the name 
            // in the format of `computer_name\user_name` so instead
            // we use %USERNAME% which gives us the exact username.
            #define USERNAME_QUERY "echo %USERNAME%" 
        #elif defined(unix) || defined(__unix__) || defined(__unix)
            #define USERNAME_QUERY "whoami"
        #endif
        auto username = execute_command(USERNAME_QUERY);
        // this line removes the white spaces (such as newline, etc)
        // from the username.
        username = std::regex_replace(username, std::regex("\\s"), "");
        return username;
        
    }
    

    这在 Linux 和 Windows 上都可以正常工作,并且兼容 C++11!

    在线测试:https://paiza.io/projects/e/xmBuf3rD7MhYca02v5V2dw?theme=twilight

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-15
      相关资源
      最近更新 更多