argc가 상수가 아닌 이유는 무엇입니까?


104
int main( const int argc , const char[] const argv)

으로 효과적인 C ++ 항목 # 3 주 "를 사용 CONST 가능한"나는 "이 '상수'매개 변수를 만들지 왜 생각을 시작 const?".

argc프로그램에서 의 값 이 수정 되는 시나리오가 있습니까?


38
당신은 선언 무료 argcconst.
Oliver Charlesworth dec.

14
나는 이것을하는 많은 생산 품질 코드를 보았다 :--argc
Aniket Inge

2
C 레거시와 관련이 있다고 생각하지만 방법을 모르겠습니다.
Luis Machuca

13
"가능할 때마다 const 사용"은 함수가 종료 된 후에도 함수 내의 모든 수정이 지속되는 참조로 전달 된 것을 참조한다고 생각합니다. 이것은 정수처럼 값으로 전달되는 것들에 대해서는 사실이 아니므로 그것을 만들어서 얻을 수있는 것은 아무것도 없습니다 const. 참으로, 통과 argcA와 const int당신이 다음 사용할 수 없음을 의미 argc기능 내부 카운터, 말,로.
Steve Melnikoff

4
@SteveMelnikoff : const값에 의한 전달 매개 변수 를 만들어 얻을 것이 없다는 데 동의하지 않습니다 . 예를 들어, 참조 stackoverflow.com/a/8714278/277304stackoverflow.com/a/117557/277304
leonbloy

답변:


114

이 경우 역사가 요인입니다. C는 이러한 입력을 "불변"으로 정의했으며 기존 C 코드와의 호환성은 C ++의 초기 목표였습니다.

와 같은 일부 UNIX API는 getopt실제로 조작을 수행 argv[]하므로 const이러한 이유로도 만들 수 없습니다 .

(참고 : 흥미롭게도, getopt의 프로토 타입이 수정 argv[]하지는 않지만 가리키는 문자열을 수정할 수 있음을 암시 하지만, Linux man 페이지는 getopt인수 를 순열 한다고 표시하고 그들이 장난 스럽다는 것을 알고있는 것처럼 보입니다 . The man page at the Open 그룹은이 순열을 언급하지 않습니다.)

퍼팅 constargcargv많이 살 것, 그리고 같은 관행, 프로그래밍 오래된 학교를 무효화 할 것입니다 :

// print out all the arguments:
while (--argc)
    std::cout << *++argv << std::endl;

나는 그런 프로그램을 C로 작성했고 나는 혼자가 아니라는 것을 알고있다. 어딘가 에서 예제를 복사했습니다 .


1
-1 Re "getopt와 같은 일부 UNIX API는 실제로 argv []를 조작하므로 이러한 이유로도 const로 만들 수 없습니다." C 함수가 수행 할 수있는 작업에 영향을주지 않고에 최상위 수준 const을 자유롭게 추가 할 수 있습니다 argv. 또한, getopt로 선언됩니다 int getopt(int argc, char * const argv[], const char *optstring);. 그리고 여기서는 const최상위 수준이 아니지만 포인터를 const수정하지 않겠다는 약속 인으로 선언 합니다 (지키는 문자열이 수정 될 수 있음).
건배와 hth. -Alf

@ Cheersandhth. - 알프는 : getopt 순서를 무작위로 바꾸어 넣argv[] 기본적으로 배열을하지만, 문자열을 수정하지 않습니다. ( permute 라는 단어 는 man 페이지에서 직접 나온 것입니다.) 이는 argv배열 자체가 const가리키는 문자열이더라도 배열 자체가 아님을 의미합니다 . argv[]배열 조작 하지 않는 방법은 무엇입니까?
조 Z

1
죄송합니다. 제가 본 문서 는 일관성이 없습니다. 서명은 그러한 순열을 허용하지 않습니다. 예를 참조하십시오 . 그러나 다음 텍스트는 영구히 작동한다고 말합니다. 그래서 저는 반대표를 제거하고 있습니다.
건배와 hth. -Alf

1
즉, 내가 반대표를 제거 할 수 있도록 "잠금 해제"를 편집해야합니다. 그리고 당신은 프로토 타입을 오해하고 있습니다. 내가 제공 한 예제와 컴파일 오류 "읽기 전용 위치 할당"을보십시오.
건배와 hth. -Alf

1
@ Cheersandhth.-Alf : 흥미 롭군요 ... 헤더에서 프로토 타입을 찾아 봤는데 char* const* ___argv거기에 있지만 인터페이스는 실제로 const char **. 그런 혼란. 에 대한 []및 의 우선 순위를 혼동 *했습니다 const. 죄송합니다.
조 Z

36

C 표준 (ISO / IEC 9899 : 2011)은 다음과 같이 말합니다.

5.1.2.2.1 프로그램 시작

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

int main(void) { /* ... */ }

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

int main(int argc, char *argv[]) { /* ... */ }

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

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

  • 의 가치 argc 음수가 아니어야합니다.
  • argv[argc] 널 포인터 여야합니다.
  • 의 값 argc이 0보다 크면 배열 구성원 argv[0]argv[argc-1] inclusive를 은 프로그램 시작 전에 호스트 환경에서 구현 정의 값을 제공하는 문자열에 대한 포인터를 포함합니다. 그 목적은 호스팅 된 환경의 다른 곳에서 프로그램을 시작하기 전에 결정된 정보를 프로그램에 제공하는 것입니다. 호스트 환경이 대문자와 소문자로 된 문자가있는 문자열을 제공 할 수없는 경우 구현은 문자열이 소문자로 수신되는지 확인해야합니다.
  • 의 값 argc이 0보다 크면로 가리키는 문자열 argv[0] 은 프로그램 이름 을 나타냅니다. argv[0][0]호스트 환경에서 프로그램 이름을 사용할 수없는 경우 널 문자가됩니다. 의 값 argc이 1보다 크면 argv[1]through가 가리키는 문자열 argv[argc-1] 은 프로그램 매개 변수 를 나타냅니다.
  • 배열이 가리키는 매개 변수 argcargv및 문자열은 argv프로그램에 의해 수정 가능해야하며 프로그램 시작과 프로그램 종료 사이에 마지막으로 저장된 값을 유지해야합니다.

10) 따라서으로 int정의 된 typedef 이름으로 대체 int되거나의 유형이 argv로 작성 될 수 있습니다 char **argv.

마지막 글 머리 기호에 유의하십시오. argc및 둘 다 argv수정 가능해야 한다고 말합니다 . 수정할 필요는 없지만 수정할 수 있습니다.


흥미 롭군. 준 관련 메모에서 Qt의 QApplication(argc,argv)생성자 argc참조 로 정의 되었기 때문에 충돌을 일으키는 버그가 발생 했습니다 . 놀랐습니다.
HostileFork은 그나마 신뢰 SE 말한다

23

argcmain()이전 날짜에 대한 함수 서명 때문에 일반적으로 상수가 아닙니다 const.

argc는 스택 변수이므로 변경해도 사용자 고유의 명령 줄 처리 외에는 영향을주지 않습니다.

물론 const원하는 경우 선언 할 수 있습니다.


8

const형식 인수 의 최상위 수준 은 함수 유형의 일부가 아닙니다. 원하는대로 추가하거나 제거 할 수 있습니다. 함수 구현에서 인수로 수행 할 수있는 작업에만 영향을줍니다.

따라서 argc자유롭게 추가 할 수 있습니다 const.

그러나 기능 서명을 변경하지 않고 argv는 문자 데이터 const를 만들 수 없습니다 . 즉, 표준 main함수 시그니처 중 하나 가 아니므로 main함수 로 인식 할 필요가 없습니다 . 그래서 좋은 생각이 아닙니다.


main장난감이 아닌 프로그램에서 표준 인수를 사용하지 않는 좋은 이유 는 Windows에서 국제 문자가있는 파일 이름과 같은 실제 프로그램 인수를 나타낼 수 없기 때문입니다. Windows에서는 Windows ANSI로 인코딩 된 매우 강력한 규칙이기 때문입니다. Windows에서는 GetCommandLineAPI 함수 측면에서 좀 더 이식 가능한 인수 액세스 기능을 구현할 수 있습니다 .


당신이 추가에서 아무것도 방지, 합산 constargc있지만, 가장 유용한 const에 -ness가 argv당신에게 표준이 아닌 줄 것입니다 main기능을, 대부분의 아마 같은 인식되지 않습니다. 다행스럽게도 (아이러니하게) 이식 가능한 심각한 코드에 대한 표준 인수를 사용하지 않는 좋은 이유가 main있습니다. 간단히 말해서, 실습에서는 영어 알파벳 문자 만있는 오래된 ASCII 만 지원합니다.


1
cygwin 또는 UTF-8을 제대로 지원하는 다른 libc를 사용하여 Windows 용으로 개발하는 경우 (내가 아는 한 cygwin은 현재 유일하지만 다른 옵션을 작업하는 사람이 있습니다) 표준 main서명이 제대로 작동하며 다음을 수행 할 수 있습니다. 임의의 유니 코드 인수를받습니다.
R .. GitHub의 STOP 돕기 ICE

@R 그들은 또한 대부분의 * nix 플랫폼에서 잘 작동합니다. 문제는 그들이 작동하는 플랫폼이 있는지 여부가 아닙니다. 그러나, 아주 좋은 이니셔티브 , 그리고 그것이 발생함에 따라 나는 똑같이, 다소 심각하게
건배와 hth. -Alf

4

의 서명은 main다소에서 역사적 유물이다 C. 역사적으로는 C하지 않았다 const.

그러나 constconst의 효과는 컴파일 시간에만 적용되므로 매개 변수를 선언 할 수 있습니다 .


"역사적 C"라고 말할 때 우리가 여기서 말하는 것은 얼마나 역사적입니까?
조 Z

8
constC89 / C90에 첨가 됨; 그 이전에, 그것은 C의 부분이 아니었던
조나단 레플러

@JonathanLeffler : 알다시피, 나는 그것을 잊었다. 저는 1992 년에 C를 배웠습니다. 그 전에는 Pascal, BASIC 및 어셈블리 해커였습니다.
Joe Z

2

왜냐하면는 argc지역 변수 (그리고 C ++에서는 참조 등이 아님)이고 특별한 장소는 main이전 버전과의 호환성 헛소리가 응용 프로그램이 const로 만들 도록 강제 할 이유없이 엄청난 양의 여유를 부여한다는 것을 의미 하기 때문 입니다.

main() {}

int main() {}

main() { return 0; }

main(int argc, char* argv[]) { return 0; }

int main(const int argc, const char** argv) { /* no return*/ }

이러한 다양한 변형은 다양한 C 및 C ++ 컴파일러에서 컴파일됩니다.

따라서 궁극적으로 argc가 const가 아니라는 것은 아닙니다. 꼭 그래야 할 필요는 없지만 원하는 경우 가능합니다.

http://ideone.com/FKldHF , C 예 :

main(const int argc, const char* argv[]) { return 0; }

http://ideone.com/m1qc9c , C ++ 예제

main(const int argc) {}

명시 적 반환 유형이없는 변형은 C11은 말할 것도없고 C99에서는 더 이상 유효하지 않지만 컴파일러는 이전 버전과의 호환성을 이유로 계속 허용합니다. C ++ 컴파일러는 반환 유형이없는 변형을 허용하지 않아야합니다.
Jonathan Leffler

@JonathanLeffler 네, 마지막 ideone 예제 ( ideone.com/m1qc9c )는 -std=c++11. Clang도 허용하지만을 제공 warning: only one parameter on 'main' declaration [-Wmain]하며 MSVC는 반환 유형 지정자 누락 및 argc에 대한 참조 부족에 대해서만 항의합니다. 다시, 'shenanigans'와 'leeway':)
kfsone

1

역사적인 이유를 제외하고 argc와 argv를 non-로 유지하는 좋은 이유 const는 컴파일러 구현이 main에 대한 인수로 무엇을 할 것인지 알지 못하기 때문입니다. 단지 해당 인수를 제공해야한다는 것을 알고 있기 때문입니다.

자체 함수 및 관련 프로토 타입을 정의 할 때 만들 수있는 매개 변수 const와 함수가 수정할 매개 변수를 알고 있습니다 .

극단적으로 생각하면 모든 함수에 대한 모든 매개 변수가 선언되어야한다고 선언 할 수 있으며 const, 변경해야 할 이유가 있다면 (예 : 배열을 검색하기 위해 인덱스를 감소) 로컬 비 const변수 를 만들어야 합니다. const인수의 값을 해당 변수에 복사하십시오 . 이는 바쁜 업무와 실질적인 이점이없는 추가 LOC를 만듭니다. 인수 값을 수정하지 않는 경우 적절한 정적 분석기가 선택되며 매개 변수를 만드는 것이 좋습니다 const.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.