Портативный способ получить имя пользователя

Для C/C++, похоже, нет переносимой функции для получения имени пользователя в Linux/Posix и Windows. Какой был бы наименее громоздкий и в то же время надежный переносимый код для достижения этой цели?

В Linux переменная окружения USER, по-видимому, всегда определена, тогда как Windows, похоже, определяет переменную USERNAME. Полагаясь на getenv, можно было бы избежать включения windows.h и минимизировать операторы препроцессора:

char * user_name = getenv("USER");
if (!user_name) {
     user_name = getenv("USERNAME");
}

Но является ли этот подход наполовину надежным? Или я не знаю другого решения? А еще я был несведущ в отношении iOS...


person tssch    schedule 30.08.2013    source источник


Ответы (4)


Портативного решения нет.

В Linux (и вообще в Unix) «пользователь» — это число, которое может иметь несколько разных имен. Используйте getuid, чтобы получить идентификатор, затем getpwuid, чтобы получить одно из имен. Или используйте getlogin, чтобы получить имя, которое пользователь использовал для входа в систему (но это будет работать, только если у процесса есть управляющий терминал). Если вы хотите получить все имена, под которыми известен пользователь, вам придется выполнить итерацию, используя getpwent, проверяя поле pw_uid для каждой возвращаемой записи.

Использование переменной окружения не гарантируется. Во многих контекстах переменная среды не будет установлена, и даже если она установлена, ее правильность не гарантируется.

В Windows есть функция GetUserName; Однако я не слишком много об этом знаю.

person James Kanze    schedule 30.08.2013

Использование переменных среды для поиска имени пользователя очень ненадежно:

Я расширил ваш код до этого:

#include <iostream>

int main()
{
    char * user_name = getenv("USER");
    std::cout << user_name << std::endl;
}

и сделал это:

$ whoami
MatsP
$ g++ -Wall -std=c++0x getenv.cpp 
$ ./a.out
MatsP
$ export USER=DonaldDuck
$ ./a.out
DonaldDuck

Итак, я определенно предлагаю, чтобы, если имя пользователя имеет какое-либо значение для вашего кода, вы должны использовать системную функцию для получения имени пользователя. Если это не важно для вашего кода, спросите во время установки или что-то в этом роде и не пытайтесь использовать какие-либо системные функции для получения имени пользователя.

(Отвечая на ваш фактический вопрос, да, я думаю, что iOS имеет ту же функциональность, что и переменная среды USER, хотя я не уверен, что на iPhone есть значимый пользователь).

person Mats Petersson    schedule 30.08.2013
comment
Если используется что-то вроде хранения результатов игр в отдельных файлах для каждого пользователя, переменная среды, вероятно, является приемлемым решением. Это позволяет одному пользователю работать под разными именами. Но игровая программа, вероятно, не будет вызываться в контексте, где переменная вообще недоступна. - person James Kanze; 30.08.2013

Концепция пользователя связана с операционной системой или даже системой, а не с языком.

Поскольку существует множество различных систем, единственный возможный подход — ограничить себя списком систем, которые вы хотите поддерживать.

Существует программное обеспечение, которое может помочь вам добиться переносимости, например, автоинструменты GNU для Unix-подобных систем (и, в некоторой степени, для Windows).

person mvw    schedule 30.08.2013

Вы правы - нет портативного способа сделать это. Для этого есть два решения: используйте правильный набор ifdef, чтобы использовать один код в окне, а другой - в linux.

другой способ - сделать это с фабрикой, которая вернет вам абстрактный объект или указатель на функцию, которая будет специфичной для системы. Фабрика должна обнаружить систему и вернуть правильную функцию/класс

person Michał Walenciak    schedule 30.08.2013
comment
Вам не нужна фабрика; просто объявите функцию, возвращающую std::string, и реализуйте ее в двух (или более) разных исходных файлах. Какой исходный файл вы фактически скомпилируете, будет зависеть от системы. - person James Kanze; 30.08.2013