Alexm
Intră

Folosește-ți e-mailul sau numele de utilizator și parola pentru a te identifica

Înscrie-te

Vei primi un e-mail cu un link de activare. Ultimul câmp este opțional


🠉

Obține argumentele liniei de comandă ca vector de wstring în C++

Dacă ai nevoie de asta, citește acest mic articol care vine cu cod complet testat și exemple de utilizare a acestuia

Tocmai am început acest nou mic proiect al meu în C++ și, deoarece aplicația trebuie să citească și să analizeze argumentele care i-au fost transmise în linia de comandă, m-am gândit că ar fi mai bine să le am pe toate stocate într-un std::std::vector. În general, tind să activez suportul pentru caractere largi în aplicațiile pe care le creez, pentru a mă asigura că pot folosi simboluri Unicode; așadar, vectorul va stoca argumentele ca obiecte std::wstring.

Am testat soluția în Windows (consolă și programe Win32 GUI) și Linux (consolă). Vei găsi mai multe informații în comentarii. Sper că vă poate fi de folos. Mai jos, codul. Eu îl am într-un fișier antet pe care îl includ în sursele CPP.


#include <cstring>
#include <string>
#include <vector>

// APLICAȚII WINDOWS CU CONSOLĂ
#if _CONSOLE

/**
 * Obține argumente ale liniei de comandă ca vector în aplicația consolei Windows
 *
 * Obține numărul de argumente și indicatorul de la punctul principal de intrare wmain
 */
std::vector<std::wstring> cmdArguments(int argc, wchar_t* argv[]) {
    return std::vector<std::wstring>(argv, argv + argc);
}

// APLICAȚII WINDOWS CU INTERFAȚĂ GRAFICĂ
#elif _WIN32

#include <shellapi.h>
#include <windows.h>

/**
 * Obține argumente ale liniei de comandă ca vector în aplicația Windows
 *
 * Opțional, se poate trece un indicator la linia de comandă
 */
std::vector<std::wstring> cmdArguments(LPWSTR lpCmdLine = NULL) {
    std::vector<std::wstring> arguments;
    LPWSTR* szArglist;
    int nArgs;

    // extrage un indicator la argumentele liniei de comandă utilizând API-ul Shell
    szArglist = CommandLineToArgvW(lpCmdLine != NULL ? lpCmdLine : GetCommandLineW(), &nArgs);
    if (szArglist != NULL) {
        for (auto i = 0; i < nArgs; i++) arguments.push_back(szArglist[i]);
    }

    LocalFree(szArglist);

    return arguments;
}

#endif

/**
 * Obține argumente ale liniei de comandă ca vector în aplicație Windows / Linux cu consolă
 *
 * Obține numărul de argumente și indicatorul de la punctul de intrare principal main
 */
std::vector<std::wstring> cmdArguments(int argc, char* argv[]) {
    std::vector<std::wstring> arguments;

    for (auto i = 0; i < argc; i++) {
        // numărul de caractere multiocteți din sursă și rezultat
        size_t mbslen = strlen(argv[i]) + 1;
        size_t mbolen;
        // indicator la argumentul cu caractere largi convertit
        wchar_t* wcs = new wchar_t[mbslen];
#ifdef _WIN32
        // în Windows putem folosi mbstowcs_s pentru a converti char în wchar_t înainte de a adăuga ca wstring la matrice
        mbstowcs_s(&mbolen, wcs, mbslen, argv[i], mbslen - 1);
#else
        // în Linux, se calculează lungimea necesară pentru a stoca argv[i] convertit într-un șir de caractere largi
        mbslen = mbstowcs(NULL, argv[i], 0);
        if (mbslen == (size_t) - 1) {
            perror("mbstowcs");
            exit(EXIT_FAILURE);
        }

        // alocă un șir de caractere largi de dimensiunea dorită + 1 pentru caracterul de terminare nul
        if (calloc(mbslen + 1, sizeof(*wcs)) == NULL) {
            perror("calloc");
            exit(EXIT_FAILURE);
        }

        // conversia șirului de caractere multioctet din arv[i] într-un șir de caractere largi
        if (mbstowcs(wcs, argv[i], mbslen + 1) == (size_t) - 1) {
            perror("mbstowcs");
            exit(EXIT_FAILURE);
        }
#endif
        arguments.push_back(std::wstring(wcs));
    }

    return arguments;
}

Urmează un exemplu al modului în care îl folosesc într-un proiect Win32 (specificarea unui indicator către linia de comandă este opțională)


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // std::vector<std::wstring> arguments = cmdArguments();
    std::vector<std::wstring> arguments = cmdArguments(lpCmdLine);

    for (const std::wstring& i : arguments) {
        MessageBox(
            NULL,
            (LPCWSTR)i.c_str(),
            (LPCWSTR)L"Argument",
            MB_ICONINFORMATION | MB_OK
        );
        wprintf(_T("%ls"), i.c_str());
    }

    return 0;
}

În Linux, am setat și localizarea, pentru a putea folosi caractere speciale


#include <iostream>

#include <locale.h>

#include "arguments.h"

int main(int argc, char* argv[])
{
    // setări regionale pentru a permite utilizarea caracterelor UNICODE în linia de comandă
    if (setlocale(LC_ALL, "en_US.UTF-8") == NULL) {
        perror("setlocale");
        exit(EXIT_FAILURE);
    }

    std::vector<std::wstring> arguments = cmdArguments(argc, argv);

    for (const std::wstring& wArg : arguments) {
        std::wcout << wArg.c_str() << "\n";
    }

    return 0;
}

Lăsați un mesaj dacă întâmpinați probleme sau dacă aveți îmbunătățiri de sugerat.