Подтвердить что ты не робот

Можно ли изменить argv или мне нужно создать скопированную копию?

В моем приложении потенциально содержится огромное количество аргументов, и я хочу, чтобы память удалялась, дублируя аргументы в отфильтрованный список. Я хотел бы отфильтровать их на месте, но я уверен, что беспорядок с самим массивом argv или с любой из данных, на которые он указывает, вероятно, не рекомендуется. Любые предложения?

4b9b3361

Ответ 1

Как только argv будет передан в основной метод, вы можете рассматривать его как любой другой массив C - измените его на месте, как вам нравится, просто знайте, что вы с ним делаете. Содержимое массива не влияет на код возврата или выполнение программы, кроме того, что вы явно делаете с ним в коде. Я не могу придумать никаких причин, по которым не было бы "целесообразно" относиться к нему специально.

Конечно, вам все равно нужно заботиться о случайном доступе к памяти за пределами argv. Обратная сторона этого доступа, как обычный массив C, заключается в том, что он также подвержен ошибкам доступа, как и любой другой обычный массив C. (Спасибо всем, кто указал на это в комментариях и других ответах!)

Ответ 2

В стандарте C99 говорится об изменении argvargc):

Параметры argc и argv и строки, на которые указывает массив argv, могут быть модифицированы программой и сохраняют свои последние сохраненные значения между запуском программы и завершением программы.

Ответ 3

В последнем проекте стандарта C (N1256) указано, что существуют две допустимые формы функции main:

int main (void);
int main (int argc, char* argv[]);

но суть - это предложение "или каким-то другим способом, определенным реализацией". Это кажется мне лазейкой в ​​стандартном достаточно большом, чтобы проехать полуприцеп.

Некоторые люди специально используют "const char *" для argv, чтобы запретить изменения аргументов. Если ваша основная функция определена таким образом, вам не разрешается изменять символы, на которые указывает argv[], о чем свидетельствует следующая программа:

pax> cat qq.c
#include <stdio.h>
int main (int c, const char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq qq.c
qq.c: In function `main':
qq.c:3: error: assignment of read-only location

Однако, если вы удалите "const", он отлично работает:

pax> cat qq2.c
#include <stdio.h>
int main (int c, char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq2 qq2.c ; ./qq2
[Xello]

Я думаю, что это также относится к С++. В текущем проекте говорится:

All implementations shall allow both of the following definitions of main:
    int main();
    int main(int argc, char* argv[]);

но он специально не запрещает другие варианты, поэтому вы предположительно можете принять версию "const" в С++ (и, фактически, g++ делает).

Единственное, что вам нужно быть осторожным, - это увеличить размер любого из элементов. Стандарты не определяют, как они хранятся, поэтому расширение одного аргумента может (возможно, повлияет на других) или других несвязанных данных.

Ответ 4

Эмпирически такие функции, как GNU getopt(), переставляют список аргументов, не вызывая проблем. Как говорит @Tim, до тех пор, пока вы играете разумно, вы можете манипулировать массивом указателей и даже отдельных строк. Просто не перекрывайте ни одну из неявных границ массива.

Ответ 5

Операционная система подталкивает argv и argc в стек аппликатора перед выполнением его, и вы можете рассматривать их как любые другие переменные стека.

Ответ 6

Единственное время, когда я скажу, что прямое манипулирование argv - плохая идея, - это когда приложение меняет свое поведение в зависимости от содержимого argv [0].

Однако изменение поведения программы в зависимости от argv [0] само по себе является очень плохой идеей, в которой переносимость является проблемой.

Кроме этого, вы можете рассматривать его так же, как и любой другой массив. Как сказал Джонатан, GNU getopt() переводит список аргументов неразрушающе, я видел другие реализации getopt(), которые доходят до сериализации и даже хэширования аргументов (полезно, когда программа приближается к ARG_MAX).

Просто будьте осторожны с вашей арифметикой указателя.

Ответ 7

Исходное распределение argv остается в качестве выбора компилятора/времени выполнения. Поэтому небезопасно изменять его волей-неволей. Многие системы строят его в стеке, поэтому он автоматически освобождается, когда основной возвращается. Другие строят его в куче и освобождают (или нет), когда основная часть возвращается.

Можно безопасно изменить значение аргумента, если вы не пытаетесь сделать его более длинным (ошибка переполнения буфера). Безопасно перемешать порядок аргументов.

Чтобы удалить аргументы, которые у вас есть preprocessed, что-то вроде этого будет работать:

(много ошибок не проверено, "--специальное" другое, для которого первый аргумент не проверен, и т.д. Это, в конце концов, просто демо-концепция.)

int main(int argc, char** argv)
{
    bool doSpecial = false; // an assumption
    if (0 == strcmp(argv[1], "--special"))
    {
        doSpecial = true; // no longer an assumption
        // remove the "--special" argument
        //  but do copy the NULL at the end.
        for(int i=1; i<argc; ++i)
            argv[i]  = argv[i+1];
        --argc;
    }
    // all normal processing with "--special" removed.
    // the doSpecial flag is available if wanted.
    return 0;
}

Но см. это для полных манипуляций: (часть библиотеки libiberty, которая используется для управления векторами вектора argv)

http://www.opensource.apple.com/source/gcc/gcc-5666.3/libiberty/argv.c

Лицензируется GNU LGPL.