기본 프로그램에 대한 표준 정의가 주어지면 :
int main(int argc, char *argv[]) {
...
}
argc
POSIX 시스템 에서 어떤 상황에서 0 이 될 수 있습니까?
답변
예, 가능합니다. 다음과 같이 프로그램을 호출하는 경우 :
execl("./myprog", NULL, (char *)NULL);
또는 또는 :
char *args[] = { NULL };
execv("./myprog", args);
그러면 “myprog”에서 argc
0이됩니다.
표준 은 또한 argc
호스팅 된 환경에서 프로그램 시작과 관련하여 섹션 5.1.2.2.1에 명시된대로 0 을 허용 합니다.
1 프로그램 시작시 호출되는 함수의 이름은
main
. 구현은이 함수에 대한 프로토 타입을 선언하지 않습니다. 반환 유형int
과 매개 변수없이 정의되어야합니다 .
int main(void) { /* ... */ }
또는 두 개의 매개 변수를 사용합니다 (여기에서
argc
및 로 지칭됩니다.argv
이름이 선언 된 함수에 로컬이기 때문에 모든 이름을 사용할 수 있음).
int main(int argc, char *argv[]) { /* ... */ }
또는 동등한 것; 또는 다른 구현 정의 방식으로.
2 선언 된 경우
main
함수에 대한 매개 변수 는 다음 제약 조건을 따라야합니다.
- 의 값은
argc
음수가 아니어야합니다.argv[argc]
널 포인터 여야합니다.…
이는 argc
0이면 argv[0]
NULL이 보장 된다는 것을 의미 합니다. 지정자에 printf
대한 인수로 사용될 때 NULL 포인터를 처리하는 방법 은 %s
표준에 나와 있지 않습니다. 이 경우 많은 구현에서 “(null)”을 출력하지만 보장되지는 않습니다.
답변
다른 답변에 추가하려면 C (POSIX 여부)에는 main ()이 프로그램 내에서 함수로 호출되는 것을 방지하는 것이 없습니다.
int main(int argc, int argv[]) {
if (argc == 0) printf("Hey!\n");
else main(0,NULL);
return 0;
}
답변
예, 0이 될 수 있습니다 argv[0] == NULL
.
argv[0]
프로그램의 이름 인 규칙입니다 . 당신은 할 수 있습니다 argc == 0
당신과 같은 바이너리를 직접 실행하는 경우 가 execve 가족 및 인수를 포기하지 않습니다. 프로그램 이름에 가깝지 않은 문자열을 지정할 수도 있습니다. 그렇기 때문에를 사용 argv[0]
하여 프로그램 이름을 얻는 것이 전적으로 신뢰할 수있는 것은 아닙니다.
일반적으로 명령 줄을 입력하는 셸은 항상 프로그램 이름을 첫 번째 인수로 추가하지만 이는 규칙입니다. 경우 argv[0]
사용 == “–help”와 getopt는을 구문 분석 옵션 때문에 당신은 그것을 감지하지 않습니다 optind
1로 초기화되지만 설정할 수 있습니다 optind
0, 사용을 getopt
표시하고 “도움말”긴 옵션을 선택합니다.
long story short : argc == 0
( argv[0]
그 자체로는 특별하지 않습니다) 가질 수 있습니다 . 런처가 전혀 주장하지 않을 때 발생합니다.
답변
초기 제안에서는 main ()에 전달 된 argc의 값이 “하나 이상”이어야했습니다. 이것은 ISO C 표준 초안의 동일한 요구 사항에 의해 주도되었습니다. 실제로 exec 함수의 호출자에게 인수가 제공되지 않은 경우 히스토리 구현은 0 값을 전달했습니다. 이 요구 사항은 ISO C 표준에서 제거되었으며 이후 POSIX.1-2017의이 볼륨에서도 제거되었습니다. 단어, 특히 단어의 사용은 Strictly Conforming POSIX 응용 프로그램이 exec 함수에 최소한 하나의 인수를 전달하도록 요구하므로 해당 응용 프로그램에서 호출 할 때 argc가 하나 이상임을 보장합니다. 실제로 많은 기존 응용 프로그램이 argc 값을 먼저 확인하지 않고 argv [0]을 참조하므로 이는 좋은 방법입니다.
Strictly Conforming POSIX 응용 프로그램에 대한 요구 사항은 또한 첫 번째 인수로 전달 된 값이 시작되는 프로세스와 관련된 파일 이름 문자열임을 명시합니다. 일부 기존 응용 프로그램은 일부 상황에서 파일 이름 문자열이 아닌 경로 이름을 전달하지만 argv [0]의 일반적인 사용이 진단 인쇄에 사용되기 때문에 파일 이름 문자열이 더 일반적으로 유용합니다. 어떤 경우에는 전달 된 파일 이름이 파일의 실제 파일 이름이 아닙니다. 예를 들어, 로그인 유틸리티의 많은 구현은 실제 파일 이름에 ( ‘-‘) 접두사를 붙이는 규칙을 사용합니다. 이것은 호출되는 명령 인터프리터에게 “로그인 쉘”임을 나타냅니다.
또한 test 및 [유틸리티는 모든 구현에서 결정적 동작을 갖기 위해 argv [0] 인수에 대한 특정 문자열이 필요합니다.
POSIX 시스템에서 argc가 0이 될 수 있습니까?
예,하지만 POSIX를 엄격하게 준수하지는 않습니다.
답변
당신이 어떤 실행 파일을 실행할 때마다 같은 ./a.out
그것은 그게 하나 개의 인수를해야합니다 program name
. 그러나 Linux에서 와 argc
같이 프로그램을 실행하는 것은 .zero
execv
empty argument list
예를 들어
int main() {
char *buf[] = { NULL };
execv("./exe", buf); /* exe is binary which it run with 0 argument */
return 0;
}
답변
요약 : 예, argv[0]
NULL이 될 수 있지만 내가 아는 좋은 / 정상적인 이유가 아닙니다. 그러나 argv[0]
NULL 인지 신경 쓰지 않는 이유가 있고, 만약 그렇다면 프로세스가 충돌하도록 특별히 허용 해야하는 이유 가 있습니다.
예, argv[0]
인수없이 실행 된 경우에만 POSIX 시스템에서 NULL이 될 수 있습니다.
더 흥미로운 실제 질문은 프로그램이 관심을 가져야한다는 것 입니다.
이에 대한 대답은 “아니요, 프로그램은 argv[0]
NULL이 아니라고 가정 할 수 있습니다 “입니다 . 일부 시스템 유틸리티 (명령 줄 유틸리티)가 작동하지 않거나 비 결정적 방식으로 작동하기 argv[0] == NULL
때문입니다. (어리 석거나 사악한 목적이 아닌) 프로세스가 왜 그렇게하는지 이유. (의 표준 사용법 getopt()
도 실패 하는지 확실하지 않지만 작동 할 것으로 예상하지 않습니다.)
많은 코드와 실제로 내가 작성한 대부분의 예제 및 유틸리티는 다음과 같은 것으로 시작합니다.
int main(int argc, char *argv[])
{
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
printf("Usage: %s [ -h | --help ]\n", argv[0]);
/* ... print usage ... */
return EXIT_SUCCESS;
}
이는 합리적 , 즉 실행되고있는 적어도 명령 경로를 제공하지 않고 다른 프로세스 Exec을하는 프로세스에 대한 더 좋은 이유가 없기 때문에 수용 가능한 execlp(cmd, cmd, NULL)
것이 아니라이 execlp(cmd, NULL)
.
(그러나 파이프 또는 소켓 명령과 관련된 타이밍 경쟁 창을 악용하는 것과 같은 몇 가지 사악한 이유를 생각할 수 있습니다. 악한 프로세스는 설정된 Unix 도메인 소켓을 통해 악의적 인 요청을 보낸 다음 즉시 승인 된 희생자 명령으로 교체됩니다 (실행 최소한의 시작 시간을 보장하기 위해 인수없이) 요청을받는 서비스가 피어 자격 증명을 확인할 때 원래의 악의적 인 프로세스 대신 희생자 명령을 볼 수 있도록합니다. SIGSEGV
악의적 인 프로세스에 더 큰 시간 창을 제공하는 “멋지게”동작하는 대신 강력 하고 빠르게 충돌하는 명령 ( NULL 포인터를 역 참조하여)
그 동안 즉, 가능한 프로세스가 서로하지만 원인이 인수없이 자체를 교체하는 것이 argc
제로로, 그런 행동은 그렇게 할 알려진 비 사악한 이유가 없다는 엄격한 의미에서 불합리하다.
이 때문에 그리고 내가 사악하고 무관심한 프로그래머와 그들의 프로그램을 위해 삶을 힘들게 만드는 것을 좋아한다는 사실 때문에 나는 개인적으로 다음과 같은 사소한 수표를 추가하지 않을 것입니다.
static int usage(const char *argv0)
{
/* Print usage using argv0 as if it was argv[0] */
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
if (argc < 1)
return usage("(this)");
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
return usage(argv[0]);
/* argv[0] and argv[1] are non-NULL, argc >= 2 */
특정 기존 사용 사례를 염두에두고있는 사람이 요청한 경우는 예외입니다. 그리고 나서도 조금 의심스러워서 먼저 사용 사례를 직접 확인하고 싶습니다.