POSIX 시스템에서 argc가 0이 될 수 있습니까?


78

기본 프로그램에 대한 표준 정의가 주어지면 :

argcPOSIX 시스템 에서 어떤 상황에서 0 이 될 수 있습니까?


12
알아 내기 위해 포인터 만 포함 int execv(const char *path, char *const argv[]);하여 시도하겠습니다 .)argvNULL

4
C 표준은 허용 argc< 1정확히 경우, 0나는 그것이 여기 port70.net/~nsz/c/c11/n1570.html#5.1.2.2.1p2
Achal

13
널리 사용되는 감안할 때 if (argc < x) { fprintf(stderr, "Usage: %s ...", argv[0]); }, 나는 확실히 볼 실제 :이 질문의 관련성

3
POSIX에 관한 정확한 규정이 아니라면 stackoverflow.com/questions/8113786/… 의 효과적인 속임수 일 것입니다
underscore_d

5
@mtraceur argv[0] || ""는 불행히도 int입니다 ...

답변:


94

예, 가능합니다. 다음과 같이 프로그램을 호출하는 경우 :

또는 또는 :

그러면 "myprog"에서 argc0이됩니다.

표준 은 또한 argc호스팅 된 환경에서 프로그램 시작과 관련하여 섹션 5.1.2.2.1에 명시된대로 0 을 허용 합니다.

1 프로그램 시작시 호출되는 함수의 이름은 main. 구현은이 함수에 대한 프로토 타입을 선언하지 않습니다. 반환 유형 int과 매개 변수없이 정의되어야합니다 .

또는 두 개의 매개 변수를 사용합니다 (여기에서 argc및 로 지칭됩니다. argv이름이 선언 된 함수에 로컬이기 때문에 모든 이름을 사용할 수 있음).

또는 동등한 것; 또는 다른 구현 정의 방식으로.

2 선언 된 경우 main함수에 대한 매개 변수 는 다음 제약 조건을 따라야합니다.

  • 의 값은 argc음수가 아니어야합니다.
  • argv[argc] 널 포인터 여야합니다.

...

이는 argc0이면 argv[0]NULL이 보장 된다는 것을 의미 합니다. 지정자에 printf대한 인수로 사용될 때 NULL 포인터를 처리하는 방법 은 %s표준에 나와 있지 않습니다. 이 경우 많은 구현에서 "(null)"을 출력하지만 보장되지는 않습니다.


7
@SylvainLeroux 당신 (이 대답을 읽는 다른 이상)이 년 전 부부의 같은 것으로, 일반적인 경우에 대한 문서뿐만 아니라, 알고 흥미 찾을 수 있습니다 하나 개의 시스템이 목표는 POSIX 호환 될 것을 사실에서 만든 다음으로 프로그램을 호출하는 것은 불가능합니다 argc == 0: OpenBSD.
mtraceur

@mtraceur, 호기심에서 : exec프로그램에 대한 인수없이 경로 만 사용하여 호출하면 OpenBSD가 무엇을 합니까? (실패? 0 번째 인수에 경로 복사?)
ilkkachu

1
@ilkkachu에 오픈 BSD는 execve오류와 함께 실패 EINVAL빈과 당신이 경우 호출 argv. 해당 조건에 대한 오류 동작은 맨 아래의 가능한 오류 목록에만 언급되어 있으므로 execve매뉴얼 페이지 에서 놓치기 쉽습니다 .
mtraceur

@mtraceur FreeBSD 허용하는 것처럼 흥미 롭습니다 .
dbush

1
@mtraceur는 varargs 부분의 NULL입니다. 0은 포인터가 아닌 정수입니다.
Antti Haapala

22

다른 답변에 추가하려면 C (POSIX 여부)에는 main ()이 프로그램 내에서 함수로 호출되는 것을 방지하는 것이 없습니다.


10
... 허. 나는 그것이 특별히 금지되어 있다고 생각했지만 C ++만이 그렇게하고 C도 괜찮습니다.
Daniel H

19

예, 0이 될 수 있습니다 argv[0] == NULL.

argv[0]프로그램의 이름 인 규칙입니다 . 당신은 할 수 있습니다 argc == 0당신과 같은 바이너리를 직접 실행하는 경우 가 execve 가족 및 인수를 포기하지 않습니다. 프로그램 이름에 가깝지 않은 문자열을 지정할 수도 있습니다. 그렇기 때문에를 사용 argv[0]하여 프로그램 이름을 얻는 것이 전적으로 신뢰할 수있는 것은 아닙니다.

일반적으로 명령 줄을 입력하는 셸은 항상 프로그램 이름을 첫 번째 인수로 추가하지만 이는 규칙입니다. 경우 argv[0]사용 == "--help"와 getopt는을 구문 분석 옵션 때문에 당신은 그것을 감지하지 않습니다 optind1로 초기화되지만 설정할 수 있습니다 optind0, 사용을 getopt표시하고 "도움말"긴 옵션을 선택합니다.

long story short : argc == 0( argv[0]그 자체로는 특별하지 않습니다) 가질 수 있습니다 . 런처가 전혀 주장하지 않을 때 발생합니다.


"하지만 optind를 0으로 설정할 수 있습니다."-이식성이 없습니다. POSIX는 "응용 프로그램이 getopt () 를 호출하기 전에 optind 를 0으로 설정 하면 동작이 지정되지 않습니다."라고 말합니다.

6
음, '--help'는 합법적 인 파일 이름이므로 argv [0]이 '--help'가 될 수없는 이유는 무엇입니까?
Tom 's

2
"그것은 관습"이라는 표현이 약간 부정확합니다. 해당 "규약"을 따르지 않는 프로그램은 POSIX를 준수하지 않습니다 (문서의 "논리"부분 참조). 따라서 다른 일을 할 수는 있지만 그렇게하는 것은 부적합합니다. 이것이 일어날 수 있기 때문에 예상해야 할 일인지 아닌지는 논쟁의 여지가 있습니다. 저는 "깨진 소프트웨어를 지원하지 않음"팀에 속해 있습니다.
Damon

3
@CharlesDuffy : 그것이 우리가 태그 수프 (HTML quirks 모드), 이메일 스팸 (SMTP 남용) 및 임의 국가의 정기적 인 인터넷 블랙홀 링 (나쁜 BGP 푸시)에 갇힌 방법입니다. 누군가가 표준을 위반하고 있으며 그렇게하도록 허용 한 역사적 이유가 없다면 실패해야합니다. 크게.
Kevin

1
@Damon 이론적 근거는 규범 적이 지 않으며, 이론적 근거가 규범 적 텍스트에 의해 뒷받침되지 않는 주장을하는 것은 이번이 처음이 아닙니다. 프로그램 이름에 대해 널 포인터를 전달하는 것이 부적합하다는 표준 텍스트를 찾을 수 없습니다.

15

초기 제안에서는 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를 엄격하게 준수하지는 않습니다.


2
"POSIX 시스템"은 "시스템의 모든 단일 프로그램이 '엄격하게 준수하는 POSIX 응용 프로그램"임을 의미합니까? 진짜 질문-나는이 문제에 대한 표준의 현학적 인 의미를 모른다. POSIX 시스템으로 인증 된 시스템을 사용하여 "Strictly Conforming POSIX Application"이 아닌 프로그램을 간단하게 작성 / 실행할 수 있다는 것을 알고 있으며, 그것이 의도 된 의미인지 확실하지 않습니다. POSIX 표준을 준수하지 않는 타사 응용 프로그램이 설치되는 순간 시스템이 부적합하다고 말하는 것입니까?
mtraceur

@mtraceur 완전히 별개의 질문 아닌가요? 이 댓글 스레드에서 답변을 기대하는지 또는 답변에 추가 정보를 추가 하려는지 확실하지 않습니다. 둘 다 이상해 보입니다.
파이프 라인

@mtraceur 프로그램이 Linux에서 실행되는 경우 프로그램이 Posix 표준에 따라 실행될 것으로 예상 할 수 있습니다. 책임은 Posix를 준수하도록 실행하는 프로그램 (일반적으로 쉘이라고도 함)에 있습니다. 즉, 쉘이 posix를 따르지 않는 것을 막는 것은 없지만 누군가가 그것을 사용할 것이라고 의심합니다.) 당신의 리눅스 배포판이 그들의 패킷에서 비 순응 Posix 프로그램을 허용한다면, 리눅스의 문제가 아닙니다.
Stargateur

@pipe이 답변의 묵시적 추론이 질문에 적용되는지 또는 오해의 소지가 있는지 판단하기 때문에 그 점에 대한 설명을 요청하고 있습니다. "예,하지만 POSIX를 엄격하게 준수하지는 않습니다"라는 대답이 나에게 보입니다. char *nothing = { 0 }; execve(*prog, nothing, nothing)시스템에서 실행될 수있는 프로그램의 단순한 존재 (또는 실행) 가 POSIX가 해당 시스템을 "엄격하게 준수하지 않음"으로 선언 하도록 논리적으로 암시합니다 . 이것은 POSIX 표준이 의도 한 바가 아닐 것 같습니까?
mtraceur 2018-04-13

@Stargateur 우리가 정말로 그것을 기대할 수 있습니까? "엄격하게 준수하는 POSIX 응용 프로그램"인 C 프로그램을 작성하고 Linux, FreeBSD 또는 최신 HP-UX 또는 Solaris 시스템 중 하나 (POSIX를 준수하는 다른 Unix에서)에서 실행한다고 가정 해 보겠습니다. 그래서 우리는 POSIX 시스템에서 엄격하게 준수하는 POSIX 응용 프로그램을 가지고 있습니다. 이제 다른 개발자가 와서 execve시스템 호출로 우리 프로그램을 호출하는 작은 프로그램을 작성합니다. 하지만 그 개발자는 작은 실수를하고 아무런 인수없이 우리를 호출합니다. 시스템 전체가 더 이상 "POSIX를 엄격하게 준수"하지 않는다고 말하는 것이 타당 합니까?
mtraceur

3

당신이 어떤 실행 파일을 실행할 때마다 같은 ./a.out그것은 그게 하나 개의 인수를해야합니다 program name. 그러나 Linux에서 와 argc같이 프로그램을 실행하는 것은 .zeroexecvempty argument list

예를 들어


3

요약 : 예, argv[0]NULL이 될 수 있지만 내가 아는 좋은 / 정상적인 이유가 아닙니다. 그러나 argv[0]NULL 인지 신경 쓰지 않는 이유가 있고, 만약 그렇다면 프로세스가 충돌하도록 특별히 허용 해야하는 이유 가 있습니다.


예, argv[0]인수없이 실행 된 경우에만 POSIX 시스템에서 NULL이 될 수 있습니다.

더 흥미로운 실제 질문은 프로그램이 관심을 가져야한다는 것 입니다.

이에 대한 대답은 "아니요, 프로그램은 argv[0] NULL이 아니라고 가정 할 수 있습니다 "입니다 . 일부 시스템 유틸리티 (명령 줄 유틸리티)가 작동하지 않거나 비 결정적 방식으로 작동하기 argv[0] == NULL때문입니다. (어리 석거나 사악한 목적이 아닌) 프로세스가 왜 그렇게하는지 이유. (의 표준 사용법 getopt()도 실패 하는지 확실하지 않지만 작동 할 것으로 예상하지 않습니다.)

많은 코드와 실제로 내가 작성한 대부분의 예제 및 유틸리티는 다음과 같은 것으로 시작합니다.

이는 합리적 , 즉 실행되고있는 적어도 명령 경로를 제공하지 않고 다른 프로세스 Exec을하는 프로세스에 대한 더 좋은 이유가 없기 때문에 수용 가능한 execlp(cmd, cmd, NULL)것이 아니라이 execlp(cmd, NULL).

(그러나 파이프 또는 소켓 명령과 관련된 타이밍 경쟁 창을 악용하는 것과 같은 몇 가지 사악한 이유를 생각할 수 있습니다. 악한 프로세스는 설정된 Unix 도메인 소켓을 통해 악의적 인 요청을 보낸 다음 즉시 승인 된 희생자 명령으로 교체됩니다 (실행 최소한의 시작 시간을 보장하기 위해 인수없이) 요청을받는 서비스가 피어 자격 증명을 확인할 때 원래의 악의적 인 프로세스 대신 희생자 명령을 볼 수 있도록합니다. SIGSEGV악의적 인 프로세스에 더 큰 시간 창을 제공하는 "멋지게"동작하는 대신 강력 하고 빠르게 충돌하는 명령 ( NULL 포인터를 역 참조하여)

그 동안 즉, 가능한 프로세스가 서로하지만 원인이 인수없이 자체를 교체하는 것이 argc제로로, 그런 행동은 그렇게 할 알려진 비 사악한 이유가 없다는 엄격한 의미에서 불합리하다.

이 때문에 그리고 내가 사악하고 무관심한 프로그래머와 그들의 프로그램을 위해 삶을 힘들게 만드는 것을 좋아한다는 사실 때문에 나는 개인적으로 다음과 같은 사소한 수표를 추가하지 않을 것입니다.

특정 기존 사용 사례를 염두에두고있는 사람이 요청한 경우는 예외입니다. 그리고 나서도 조금 의심스러워서 먼저 사용 사례를 직접 확인하고 싶습니다.


프로그램이 좋은 / 정상 / 사악하지 않은 사용 사례에 대해주의 깊게 작성되었는지 확인하기 위해 프로그램을 확인하는 것을 고려하십니까? 내가 사용하는 모든 새 프로그램을 정기적으로 호출하기 때문에 다른 "일어나지 않아야하거나 수행해서는 안되는"상황에서 프로그램에서 어떤 종류의 동작을 기대할 수 있는지를 빠르게 추정하기 위해 인수가 0 인 상태로 사용합니다. 나는 심지어이 명령 줄 도구를 내가 쓰기 코드에 대한 모든 시간을 (비록 인정 하듯이 내가 일반적으로 제로 번째 인수를 제어하기위한 많은 도구를 썼다)하지 않고 신속하고 쉽게 할 수 있습니다.
mtraceur

@mtraceur : 일반적으로 예,하지만이 특별한 경우에는 아니요. 이것은 단순히 비 인수 사례에 적절한 사용 사례가 없다고 생각하기 때문입니다 (내가 알고있는). 그러나 적어도 하나의 악의적 인 사용 사례가 있습니다. 그리고 악의적 인 사용 사례는 가능한 한 빨리 프로그램이 죽는 것에 의해 가장 잘 패배합니다 (그리고 SIGSEGV로 인해 좋은 방법입니다). 나는 인수가없는 경우를 확인하는 것이 프로그램 이 "발생하지 않아야하는" 유형의 상황 에서 정상적으로 작동하는지 여부를 나타내는 어떤 종류의 표시라고 생각하지 않습니다 .
Nominal Animal

@mtraceur : 한 가지 예는 write()-1이 아닌 음수 값을 반환하는 (저수준 C 함수, Linux의 syscall 래퍼)입니다. 단순히 발생해서는 안되므로 대부분의 프로그래머는이를 테스트하지 않습니다. 그러나 Linux에서 커널 파일 시스템 버그로 인해 2GiB 이상의 쓰기가 발생했습니다. (현재 쓰기는 다른 파일 시스템 드라이버에서 유사한 버그를 피하기 위해 syscall 수준에서 2GiB 미만으로 제한됩니다.)이 경우를 확인하는 코드는 제가 본 유일한 코드입니다. (나는 그것을 EIO오류 로 취급한다 .) 그러나 내가 말했듯이, 나는 argc == 0내 코드에서 확인하지 않기로 결정했다 .
Nominal Animal

나는 귀하의 관점과 접근 방식이 가치 있다고 생각하기 때문에 귀하의 답변을 +1하기로 결정했습니다. 나는 더 많은 사람들이 일어날 수있는 모든 코너 케이스를 다룰 것인지 (또는 다루지 않을 것인지) 비판적이고 신중하게 생각하기를 바랍니다.
mtraceur

내가 틀렸다면 정정 해줘 : C 표준이 실제로 죽어가는-로 이른 것과 같이 가능한 커녕, 어떤 제정신 동작을 보장 하는가, 당신은 역 참조하면 argv[0]argc == 0? 그것은 다시 정의되지 않은 동작을 의미하는 널 포인터를 역 참조하지 않습니까? 코드가 실행될 모든 C 구현이 합리적인 작업을 수행 할 것이라고 확신하십니까?
mtraceur
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.