code

argv 변경이 가능한가요 아니면 수정본을 만들어야 하나요?

starcafe 2023. 11. 4. 13:11
반응형

argv 변경이 가능한가요 아니면 수정본을 만들어야 하나요?

제 애플리케이션에는 잠재적으로 엄청난 수의 인수가 전달될 가능성이 있기 때문에 인수를 필터링된 목록에 복제하는 경우의 기억을 피하고 싶습니다.나는 그것들을 제자리에서 필터링하고 싶지만 argv 배열 자체나 그것이 가리키는 데이터를 엉망으로 만드는 것은 아마도 바람직하지 않을 것이라고 꽤 확신합니다.좋은 의견이라도 있나?

C99 표준은 수정에 대해 이렇게 말합니다.argv(그리고argc):

매개 변수 argc 및 argv와 argv 배열이 가리키는 문자열은 프로그램에 의해 수정 가능해야 하며, 프로그램 시작과 프로그램 종료 사이에 마지막으로 저장된 값을 유지해야 합니다.

argv가 메인 메소드로 전달되면 다른 C 어레이처럼 처리할 수 있습니다. 원하는 대로 위치를 변경하고, 사용 중인 작업에 주의하십시오.배열의 내용은 코드에서 명시적으로 수행하는 것 이외에는 반환 코드나 프로그램 실행에 영향을 미치지 않습니다.특별히 치료하는 것이 "좋지 않은" 이유는 전혀 생각할 수 없습니다.

물론 argv의 한계를 넘어 메모리에 실수로 접근하는 것에 대해서는 여전히 주의가 필요합니다.일반 C 어레이처럼 접근이 가능한 장점은 다른 일반 C 어레이와 마찬가지로 오류에 접근하기 쉽다는 것입니다. (댓글 등에서 이를 지적해주신 모든 분들께 감사드립니다!)

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]

C++도 마찬가지라고 생각합니다.현재 초안에는 다음과 같이 명시되어 있습니다.

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

하지만 다른 변형들을 특별히 허용하지 않기 때문에 당신은 아마도 a를 받아들일 수 있을 것입니다."const"C++ 버전도 있습니다. (그리고, 사실, g++는 가능합니다.)

주의해야 할 것은 모든 요소의 크기를 늘리려는 것입니다.표준은 저장 방법을 규정하지 않으므로 하나의 인수를 확장하면 다른 인수나 관련 없는 다른 데이터에 영향을 미칠 수 있습니다.

경험적으로 GNU getopt()와 같은 함수는 문제를 일으키지 않고 인수 목록을 순열합니다.@Tim의 말처럼, 센스 있게 플레이하기만 하면 포인터 배열은 물론 개별 문자열까지 조작할 수 있습니다.암시적 배열 경계를 초과하지 마십시오.

몇몇 도서관들은 이렇게 합니다!

glut opengl 라이브러리(GlutInit)에 의해 제공되는 초기화 방법은 glut 관련 인수를 스캔하고, 후속 요소를 이동시킴으로써 삭제합니다.argv앞으로(실제 문자열이 아닌 포인터 이동) 및 감소 argc

2.1

glutInit glutInit은 GLUT 라이브러리를 초기화하는 데 사용됩니다.

사용.

void glutInit(int *argcp, char **argv);

argcp

메인에서 수정되지 않은 프로그램의 argc 변수에 대한 포인터.glutInit은 GLUT 라이브러리를 위해 의도된 명령줄 옵션을 추출하므로 반환 시 argcp가 가리키는 값이 업데이트됩니다.

argv

메인에서 수정되지 않은 argv 변수입니다.argcp와 마찬가지로 argv에 대한 데이터는 glutInit가 GLUT 라이브러리에서 이해하는 모든 명령줄 옵션을 추출하기 때문에 업데이트됩니다.

argv와 argc를 실행하기 전에 argv와 argc를 스택의 응용 프로그램에 밀어넣으면 다른 스택 변수와 같이 처리할 수 있습니다.

argv를 직접 조작하는 것이 나쁜 생각이라고 말할 수 있는 유일한 경우는 argv[0]의 내용에 따라 애플리케이션이 동작을 변경할 때입니다.

그러나 argv[0]에 따라 프로그램의 동작을 변경하는 것은 휴대성이 문제가 되는 그 자체로 매우 나쁜 생각입니다.

그 외에는 다른 어레이와 마찬가지로 취급할 수 있습니다.조나단이 말했듯이 GNU getopt()는 인수 목록을 비파괴적으로 순열합니다. 저는 인수를 직렬화하고 해쉬하는 데까지 이르는 다른 getopt() 구현을 본 적이 있습니다(프로그램이 ARG_MAX에 근접할 때 유용함).

그냥 포인터 연산에 주의하세요.

의 원래 할당.argv는 컴파일러/runtime 선택으로 남겨집니다.따라서 임의로 수정하는 것은 안전하지 않을 수 있습니다.많은 시스템이 스택 위에 구축하기 때문에 메인이 반환될 때 자동으로 할당 해제됩니다.다른 방법으로 힙 위에 빌드하고, 메인이 반환되면 해제(또는 해제)합니다.

인수 값을 길게 하지 않는 한(버퍼 오버런 오류) 인수 값을 변경하는 것이 안전합니다.논쟁의 순서를 섞는 것은 안전합니다.

사전 처리한 인수를 제거하려면 다음과 같은 작업을 수행합니다.

( 많은 오류 조건이 확인되지 않음, 첫 번째 arg가 확인되지 않은 "--special" 등입니다.이는 결국 개념 시연에 불과합니다. )

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;
}

그러나 완전한 조작을 위해 이것을 참조하십시오: (argv 스타일 벡터를 조작하는 데 사용되는 liberty 라이브러리의 부분)

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

라이선스된 GNU LGPL입니다.

언급URL : https://stackoverflow.com/questions/963493/is-it-possible-to-change-argv-or-do-i-need-to-create-an-adjusted-copy-of-it

반응형