왜 main ()이 짧아야합니까?


87

저는 9 년 넘게 프로그래밍을 해왔으며, 첫 프로그래밍 교사의 조언에 따라 항상 main()기능을 매우 짧게 유지 합니다.

처음에는 왜 그런지 몰랐습니다. 나는 교수님의 기쁨에 크게 이해하지 않고 순종했습니다.

경험을 얻은 후에 코드를 올바르게 디자인하면 짧은 main()기능이 발생한다는 것을 알았습니다. 모듈화 된 코드를 작성하고 단일 책임 원칙을 따르면 내 코드를 "번치"로 설계 할 수 있었으며 main()프로그램을 실행할 수있는 촉매제 역할 만했습니다.

몇 주 전에 빨리 파이썬의 소스 코드를보고 있었고 main()함수를 찾았습니다 .

/* Minimal main program -- everything is loaded from the library */

...

int
main(int argc, char **argv)
{
    ...
    return Py_Main(argc, argv);
}

예이 파이썬. 짧은 main()기능 == 좋은 코드.

프로그래밍 교사가 옳았습니다.

더 깊게보고 싶을 때 Py_Main을 살펴 보았습니다. 전체적으로 다음과 같이 정의됩니다.

/* Main program */

int
Py_Main(int argc, char **argv)
{
    int c;
    int sts;
    char *command = NULL;
    char *filename = NULL;
    char *module = NULL;
    FILE *fp = stdin;
    char *p;
    int unbuffered = 0;
    int skipfirstline = 0;
    int stdin_is_interactive = 0;
    int help = 0;
    int version = 0;
    int saw_unbuffered_flag = 0;
    PyCompilerFlags cf;

    cf.cf_flags = 0;

    orig_argc = argc;           /* For Py_GetArgcArgv() */
    orig_argv = argv;

#ifdef RISCOS
    Py_RISCOSWimpFlag = 0;
#endif

    PySys_ResetWarnOptions();

    while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
        if (c == 'c') {
            /* -c is the last option; following arguments
               that look like options are left for the
               command to interpret. */
            command = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (command == NULL)
                Py_FatalError(
                   "not enough memory to copy -c argument");
            strcpy(command, _PyOS_optarg);
            strcat(command, "\n");
            break;
        }

        if (c == 'm') {
            /* -m is the last option; following arguments
               that look like options are left for the
               module to interpret. */
            module = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (module == NULL)
                Py_FatalError(
                   "not enough memory to copy -m argument");
            strcpy(module, _PyOS_optarg);
            break;
        }

        switch (c) {
        case 'b':
            Py_BytesWarningFlag++;
            break;

        case 'd':
            Py_DebugFlag++;
            break;

        case '3':
            Py_Py3kWarningFlag++;
            if (!Py_DivisionWarningFlag)
                Py_DivisionWarningFlag = 1;
            break;

        case 'Q':
            if (strcmp(_PyOS_optarg, "old") == 0) {
                Py_DivisionWarningFlag = 0;
                break;
            }
            if (strcmp(_PyOS_optarg, "warn") == 0) {
                Py_DivisionWarningFlag = 1;
                break;
            }
            if (strcmp(_PyOS_optarg, "warnall") == 0) {
                Py_DivisionWarningFlag = 2;
                break;
            }
            if (strcmp(_PyOS_optarg, "new") == 0) {
                /* This only affects __main__ */
                cf.cf_flags |= CO_FUTURE_DIVISION;
                /* And this tells the eval loop to treat
                   BINARY_DIVIDE as BINARY_TRUE_DIVIDE */
                _Py_QnewFlag = 1;
                break;
            }
            fprintf(stderr,
                "-Q option should be `-Qold', "
                "`-Qwarn', `-Qwarnall', or `-Qnew' only\n");
            return usage(2, argv[0]);
            /* NOTREACHED */

        case 'i':
            Py_InspectFlag++;
            Py_InteractiveFlag++;
            break;

        /* case 'J': reserved for Jython */

        case 'O':
            Py_OptimizeFlag++;
            break;

        case 'B':
            Py_DontWriteBytecodeFlag++;
            break;

        case 's':
            Py_NoUserSiteDirectory++;
            break;

        case 'S':
            Py_NoSiteFlag++;
            break;

        case 'E':
            Py_IgnoreEnvironmentFlag++;
            break;

        case 't':
            Py_TabcheckFlag++;
            break;

        case 'u':
            unbuffered++;
            saw_unbuffered_flag = 1;
            break;

        case 'v':
            Py_VerboseFlag++;
            break;

#ifdef RISCOS
        case 'w':
            Py_RISCOSWimpFlag = 1;
            break;
#endif

        case 'x':
            skipfirstline = 1;
            break;

        /* case 'X': reserved for implementation-specific arguments */

        case 'U':
            Py_UnicodeFlag++;
            break;
        case 'h':
        case '?':
            help++;
            break;
        case 'V':
            version++;
            break;

        case 'W':
            PySys_AddWarnOption(_PyOS_optarg);
            break;

        /* This space reserved for other options */

        default:
            return usage(2, argv[0]);
            /*NOTREACHED*/

        }
    }

    if (help)
        return usage(0, argv[0]);

    if (version) {
        fprintf(stderr, "Python %s\n", PY_VERSION);
        return 0;
    }

    if (Py_Py3kWarningFlag && !Py_TabcheckFlag)
        /* -3 implies -t (but not -tt) */
        Py_TabcheckFlag = 1;

    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
        Py_InspectFlag = 1;
    if (!saw_unbuffered_flag &&
        (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
        unbuffered = 1;

    if (!Py_NoUserSiteDirectory &&
        (p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0')
        Py_NoUserSiteDirectory = 1;

    if ((p = Py_GETENV("PYTHONWARNINGS")) && *p != '\0') {
        char *buf, *warning;

        buf = (char *)malloc(strlen(p) + 1);
        if (buf == NULL)
            Py_FatalError(
               "not enough memory to copy PYTHONWARNINGS");
        strcpy(buf, p);
        for (warning = strtok(buf, ",");
             warning != NULL;
             warning = strtok(NULL, ","))
            PySys_AddWarnOption(warning);
        free(buf);
    }

    if (command == NULL && module == NULL && _PyOS_optind < argc &&
        strcmp(argv[_PyOS_optind], "-") != 0)
    {
#ifdef __VMS
        filename = decc$translate_vms(argv[_PyOS_optind]);
        if (filename == (char *)0 || filename == (char *)-1)
            filename = argv[_PyOS_optind];

#else
        filename = argv[_PyOS_optind];
#endif
    }

    stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0);

    if (unbuffered) {
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
        _setmode(fileno(stdin), O_BINARY);
        _setmode(fileno(stdout), O_BINARY);
#endif
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
#else /* !HAVE_SETVBUF */
        setbuf(stdin,  (char *)NULL);
        setbuf(stdout, (char *)NULL);
        setbuf(stderr, (char *)NULL);
#endif /* !HAVE_SETVBUF */
    }
    else if (Py_InteractiveFlag) {
#ifdef MS_WINDOWS
        /* Doesn't have to have line-buffered -- use unbuffered */
        /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
#else /* !MS_WINDOWS */
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IOLBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
#endif /* HAVE_SETVBUF */
#endif /* !MS_WINDOWS */
        /* Leave stderr alone - it should be unbuffered anyway. */
    }
#ifdef __VMS
    else {
        setvbuf (stdout, (char *)NULL, _IOLBF, BUFSIZ);
    }
#endif /* __VMS */

#ifdef __APPLE__
    /* On MacOS X, when the Python interpreter is embedded in an
       application bundle, it gets executed by a bootstrapping script
       that does os.execve() with an argv[0] that's different from the
       actual Python executable. This is needed to keep the Finder happy,
       or rather, to work around Apple's overly strict requirements of
       the process name. However, we still need a usable sys.executable,
       so the actual executable path is passed in an environment variable.
       See Lib/plat-mac/bundlebuiler.py for details about the bootstrap
       script. */
    if ((p = Py_GETENV("PYTHONEXECUTABLE")) && *p != '\0')
        Py_SetProgramName(p);
    else
        Py_SetProgramName(argv[0]);
#else
    Py_SetProgramName(argv[0]);
#endif
    Py_Initialize();

    if (Py_VerboseFlag ||
        (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) {
        fprintf(stderr, "Python %s on %s\n",
            Py_GetVersion(), Py_GetPlatform());
        if (!Py_NoSiteFlag)
            fprintf(stderr, "%s\n", COPYRIGHT);
    }

    if (command != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    if (module != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c'
           so that PySys_SetArgv correctly sets sys.path[0] to ''
           rather than looking for a file called "-m". See
           tracker issue #8202 for details. */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);

    if ((Py_InspectFlag || (command == NULL && filename == NULL && module == NULL)) &&
        isatty(fileno(stdin))) {
        PyObject *v;
        v = PyImport_ImportModule("readline");
        if (v == NULL)
            PyErr_Clear();
        else
            Py_DECREF(v);
    }

    if (command) {
        sts = PyRun_SimpleStringFlags(command, &cf) != 0;
        free(command);
    } else if (module) {
        sts = RunModule(module, 1);
        free(module);
    }
    else {

        if (filename == NULL && stdin_is_interactive) {
            Py_InspectFlag = 0; /* do exit on SystemExit */
            RunStartupFile(&cf);
        }
        /* XXX */

        sts = -1;               /* keep track of whether we've already run __main__ */

        if (filename != NULL) {
            sts = RunMainFromImporter(filename);
        }

        if (sts==-1 && filename!=NULL) {
            if ((fp = fopen(filename, "r")) == NULL) {
                fprintf(stderr, "%s: can't open file '%s': [Errno %d] %s\n",
                    argv[0], filename, errno, strerror(errno));

                return 2;
            }
            else if (skipfirstline) {
                int ch;
                /* Push back first newline so line numbers
                   remain the same */
                while ((ch = getc(fp)) != EOF) {
                    if (ch == '\n') {
                        (void)ungetc(ch, fp);
                        break;
                    }
                }
            }
            {
                /* XXX: does this work on Win/Win64? (see posix_fstat) */
                struct stat sb;
                if (fstat(fileno(fp), &sb) == 0 &&
                    S_ISDIR(sb.st_mode)) {
                    fprintf(stderr, "%s: '%s' is a directory, cannot continue\n", argv[0], filename);
                    fclose(fp);
                    return 1;
                }
            }
        }

        if (sts==-1) {
            /* call pending calls like signal handlers (SIGINT) */
            if (Py_MakePendingCalls() == -1) {
                PyErr_Print();
                sts = 1;
            } else {
                sts = PyRun_AnyFileExFlags(
                    fp,
                    filename == NULL ? "<stdin>" : filename,
                    filename != NULL, &cf) != 0;
            }
        }

    }

    /* Check this environment variable at the end, to give programs the
     * opportunity to set it from Python.
     */
    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
    {
        Py_InspectFlag = 1;
    }

    if (Py_InspectFlag && stdin_is_interactive &&
        (filename != NULL || command != NULL || module != NULL)) {
        Py_InspectFlag = 0;
        /* XXX */
        sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0;
    }

    Py_Finalize();
#ifdef RISCOS
    if (Py_RISCOSWimpFlag)
        fprintf(stderr, "\x0cq\x0c"); /* make frontend quit */
#endif

#ifdef __INSURE__
    /* Insure++ is a memory analysis tool that aids in discovering
     * memory leaks and other memory problems.  On Python exit, the
     * interned string dictionary is flagged as being in use at exit
     * (which it is).  Under normal circumstances, this is fine because
     * the memory will be automatically reclaimed by the system.  Under
     * memory debugging, it's a huge source of useless noise, so we
     * trade off slower shutdown for less distraction in the memory
     * reports.  -baw
     */
    _Py_ReleaseInternedStrings();
#endif /* __INSURE__ */

    return sts;
}

전능하신 하나님 ... 타이타닉을 침몰시킬만큼 큽니다.

마치 파이썬이 "Intro to Programming 101"트릭을 수행하고 모든 main()코드를 "main"과 매우 유사한 다른 함수 로 옮긴 것처럼 보입니다 .

내 질문은 다음과 같습니다.이 코드가 끔찍하게 작성되었거나 짧은 주요 기능을 수행 해야하는 다른 이유가 있습니까?

지금 당장이 작업을 수행하는 것과 코드를 Py_Main()다시로 이동하는 것 사이에는 아무런 차이가 없습니다 main(). 나는 이것을 잘못 생각하고 있습니까?



38
@ 루진 나는 누군가에게 파이썬의 소스 코드를 검토하도록 요구하지 않습니다. 이것은 프로그래밍 문제입니다.
riwalk 2016 년

3
TBH, 절반 코드는 옵션 처리이며, 프로그램이 많은 옵션을 지원할 때마다 사용자 정의 프로세서를 작성하면 이것이 끝납니다.
Nim

7
@Star No, Programmers.SE는 모범 사례, 코딩 스타일 등을위한 것이기도합니다. 실제로 사이트를 방문하는 것입니다.
Mateen Ulhaq 2016 년

4
@Nim, 나는 그것이 무엇을하고 있는지 이해하지만, 그것을 쓰기하지 않을 이유가없는 options = ParseOptionFlags(argc,argv)경우 optionsA는 struct변수가 포함는 Py_BytesWarningFlag, Py_DebugFlag, 등 ...
riwalk

답변:


137

main라이브러리에서 내보낼 수는 없지만 내보낼 수 있으며 Py_Main해당 라이브러리를 사용하는 사람은 누구나 같은 프로그램에서 다른 인수로 Python을 여러 번 "호출"할 수 있습니다. 이 시점 python에서 라이브러리 함수의 랩퍼에 지나지 않고 라이브러리의 다른 소비자가됩니다. Py_Main다른 사람들과 똑같이 부릅니다 .


1
좋은 대답이 있습니다.
riwalk 2016 년

26
@Shoosh를 가져올 수 없다고 말하는 것이 더 정확하다고 가정합니다 . C ++ 표준은 자신의 코드에서 호출하는 것을 금지합니다. 게다가, 그 연계는 구현 정의되어 있습니다. 또한 main효과적으로 호출 에서 돌아옵니다. exit일반적으로 라이브러리는 원하지 않습니다.
Rob Kennedy

3
@Coder, C ++ 03 §3.6.1 / 5 참조 : "에서 return 문 main은 주 함수를 떠나고 exit반환 값을 인수로 호출하는 효과가 있습니다." 또한 호출 할 때 "정적 저장 기간이있는 객체가 손상됨"및 "모든 열린 C 스트림이 플러시됩니다"는 §18.3 / 8을 참조하십시오 exit. C99의 언어는 비슷합니다.
Rob Kennedy

1
@Coder, exitmain이 관련이 없는지 여부 . 의 행동에 대해서는 논의하지 않습니다 exit. 의 동작에 대해 논의 중입니다 main. 그리고의 동작은 main 포함 의 동작 exit이있을 수 있습니다 무엇을. 그것이 수입하고 전화하는 것이 바람직하지 않은 main이유입니다 (이러한 일이 가능하거나 허용되는 경우).
Rob Kennedy

3
@Coder,에서 복귀 해도 컴파일러 main를 호출 exit해도 효과 가 없으면 컴파일러는 표준을 따르지 않습니다. 표준이 그러한 행동을 지시 main한다는 것은 그에 특별한 무언가 있음 을 증명 합니다. 특별한 점 main은 그것에서 돌아 오는 것은 호출하는 효과가 있다는 것 exit입니다. ( 어떻게 그것은 그 작가를 컴파일러에게 달려 않습니다 단순히 정적 객체를 파괴 호출 함수 에필로그 코드를 삽입 할 수 컴파일러. atexit프로그램 루틴을, 파일을 플러시 및 종료 - 다시, 도서관에서 원하는 것이 아니다 .)
Rob Kennedy

42

그것은 그 아니다 main당신은 피해야 한 많이 안 어떤 너무 오래되고 기능. main단지 특별한 기능의 경우입니다. 더 긴 기능은 grok하기가 매우 어려워지고, 유지 보수성이 떨어지며, 일반적으로 작업하기가 더 어렵습니다. 함수를 main짧게 유지 하면 일반적으로 코드 품질이 향상됩니다.

귀하의 예에서 코드를 다른 곳으로 옮기는 데는 아무런 이점이 없습니다 main.


9
황금 단어는 "재사용"일 수 있습니다. 오랫동안 main재사용 할 수는 없습니다.
S.Lott

1
@S-그것은 하나의 황금 단어입니다. 또 다른 하나는 OMG입니다! ADHD 그냥 킥 !!!! 또는 평신도 용어 : 가독성.
Edward Strange

3
main ()에는 다른 함수에는없는 몇 가지 제한 사항이 있습니다.
Martin York

1
또한 main ()은 실제 의미가 없습니다. 코드는 모두 다른 프로그래머에게 의미가 있어야합니다. 나는 main을 사용하여 인수를 파싱하고 그 결과입니다. 몇 줄 이상인 경우에도 위임합니다.
Bill K

@Bill K : main ()을 사용하여 인수를 구문 분석하고 나머지 프로그램을 시작하는 것 역시 단일 책임 원칙을 따릅니다.
Giorgio

28

main()짧게 만드는 한 가지 이유 는 단위 테스트와 관련이 있습니다. main()단위 테스트 할 수없는 함수이므로 대부분의 동작을 단위 테스트 할 수있는 다른 클래스로 추출하는 것이 좋습니다. 이것은 당신이 말한 것과 함께갑니다

모듈화 된 코드를 작성하고 단일 책임 원칙에 따라 내 코드를 "번치"로 디자인 할 수 있었고 main ()은 프로그램을 실행하기위한 촉매제 역할을했습니다.

참고 : 나는 여기서 아이디어를 얻었습니다 .


또 다른 좋은 것. 그런 측면을 생각하지 마십시오.
riwalk

16

main길다 는 것은 좋은 생각 이 아닙니다. 에서와 같이 어떤 이 긴인지 기능 (또는 방법) 당신은 아마 리팩토링을위한 기회를 놓치고있어.

위에서 언급 한 특정 경우에는 main복잡성이 모두 고려되기 때문에 짧습니다 Py_Main. 코드가 파이썬 쉘처럼 동작하기를 원한다면 많은 코드를 다루지 않고도 해당 코드를 사용할 수 있습니다. ( main라이브러리에 넣으면 제대로 작동하지 않으므로 그렇게하면 이상한 일이 발생합니다.)

편집 :
명확히하려면 main정적 라이브러리에 명시 적으로 연결되어 있지 않으므로 올바르게 링크되지 않기 때문에 정적 라이브러리에있을 수 없습니다 (오직 끔찍한 참조가있는 객체 파일에 배치하지 않는 한) !) 많은 라이브러리에서 공유 라이브러리는 부트 스트랩 섹션이없는 실행 파일 일 main뿐이지 만 마지막으로 가장 눈에 잘 띄는 부분입니다. ).


1
즉, main도서관에 두지 마십시오 . 그것은 작동하지 않거나 당신을 몹시 혼란스럽게 할 것입니다. 그러나 함수에 거의 모든 작업을 위임 이다 lib 디렉토리에, 그것은 종종 합리적입니다.
Donal Fellows

6

모든 기능이 짧아야하는 것과 같은 이유로 Main은 짧아야합니다. 인간의 두뇌는 많은 양의 분할되지 않은 데이터를 메모리에 한 번에 유지하는 데 어려움을 겪고 있습니다. 논리적 덩어리로 나누어 다른 개발자 (자신뿐만 아니라!)도 쉽게 소화하고 추론 할 수 있습니다.

그렇습니다. 여러분의 모범은 끔찍하고 읽기 어려우며 유지하는 것은 물론입니다.


예, 나는 코드 자체가 끔찍하다고 항상 의심했습니다 (질문은 코드 자체가 아니라 코드 배치를 다루었지만). 결과적으로 파이썬에 대한 나의 비전이 본질적으로 손상되었다는 것이 두렵습니다.
11

1
@ stargazer : 코드 자체가 끔찍하다는 것을 알지 못합니다. 인간 소비를 위해 잘 정리되지 않았다는 것입니다. 즉, 잘 작동하고 성능이 뛰어난 "추악한"코드가 많이 있습니다. 코드의 아름다움이 전부는 아니지만 항상 가장 깨끗한 코드를 작성하기 위해 최선을 다해야합니다.
Ed S.

meh. 나에게, 그들은 하나이며 동일합니다. 깨끗한 코드는 더 안정적인 경향이 있습니다.
riwalk

코드는 끔찍하지 않습니다. 주로 스위치 케이스와 여러 플랫폼을 처리합니다. 정확히 뭐가 끔찍한가요?
프란체스코

@Francesco : 유감스럽게도 유지 보수 및 가독성 관점에서 "Terrible"은 기능적인 것이 아닙니다.
Ed S.

1

어떤 사람들은 아무것도하지 않는 50 가지 이상의 기능을 즐기지 만 다른 기능을 호출합니다. 오히려 주 프로그램 논리를 수행하는 일반적인 주 기능을 선호합니다. 물론 잘 구성되어 있습니다.

int main()
{
CheckInstanceCountAndRegister();
InitGlobals();
ProcessCmdParams();
DoInitialization();
ProgramMainLoopOrSomething();
DeInit();
ClearGlobals();
UnregisterInstance();
return 0; //ToMainCRTStartup which cleans heap, etc.
}

왜 래퍼 안에 무언가를 포장 해야하는지 이유가 없습니다.

순전히 개인적인 취향입니다.


1
코드이기 때문에 문서입니다. 주석을 작성할 필요없이이 방법으로 코드를 작성할 수 있습니다. 코드를 변경하면 설명서가 자동으로 변경됩니다 :-).
Oliver Weiler

1

기본 기능뿐만 아니라 모든 기능을 짧게 유지하는 것이 가장 좋습니다. 그러나 "짧은"은 주관적이며 프로그램의 크기와 사용중인 언어에 따라 다릅니다.


0

에 대한 요구 사항이 없습니다 main코딩 표준 이외의 어떠한 길이 될하려면. main함수는 다른 함수이므로 복잡도 는 10 미만이어야합니다 (또는 코딩 표준에 따라 다름). 그게 다야, 다른 것은 오히려 논쟁 적입니다.

편집하다

main짧아서는 안됩니다. 아니면 길다. 설계에 따라 수행하고 코딩 표준을 준수하는 데 필요한 기능을 포함해야합니다.

귀하의 질문에있는 특정 코드에 관해서는 그렇습니다.

두 번째 질문에 관해서는 - 그래, 당신은 잘못 . 모든 코드를 다시 메인으로 옮기면 Py_Main외부에서 링크하여 모듈로 라이브러리로 사용할 수 없습니다 .

지금은 분명합니까?


나는 그것이 길 있는지 묻지 않았다 . 나는 왜 그렇게 길지 않아야 하는지 물었다 .
riwalk 2016 년

“10 이하의 유연성”? 이에 대한 측정 단위가 있습니까?
Donal Fellows

@ Stargazer712 함수 길이는 일반적으로 코딩 표준에 의해서도 조절됩니다. 가독성 문제 (및 복잡성, 일반적으로 긴 함수는 분기되어 복잡성이 20 이상으로 나뉘어 있음)이며 앞에서 말했듯 main이이 점에서 다른 함수와 다르지 않습니다.
littleadv 2016 년

@Donal-예, 링크를 클릭하십시오.
littleadv 2016 년

이 새싹을 내려 놓아야합니다. 질문의 의도가 완전히 없습니다.
riwalk 2016 년

0

다음은 GCC 4.6.1 Changelog 에서 간결한 새로운 실용적인 이유입니다 .

이름이 지정된 섹션 지원이있는 대부분의 대상에서 시작시에만 사용되는 함수 (정적 생성자 및 main ), 종료시에만 사용되는 함수 및 콜드로 감지 된 함수는 별도의 텍스트 세그먼트 하위 섹션에 배치됩니다 . 이것은 -freorder-functions 기능을 확장하고 동일한 스위치로 제어됩니다. 큰 C ++ 프로그램의 시작 시간을 향상시키는 것이 목표입니다.

내가 추가 한 강조 표시.


0

약간의 소프트웨어 만 있으면 해당 소프트웨어의 모든 코드가 양호하다고 가정하지 마십시오. 좋은 소프트웨어와 좋은 코드는 같은 것이 아니며 좋은 코드로 좋은 소프트웨어를 뒷받침하더라도 큰 프로젝트에는 표준이 떨어지는 곳이있을 수밖에 없습니다.

짧은 main기능 을 갖는 것은 좋은 습관 이지만 실제로는 짧은 기능을 갖는 것이 더 나은 일반적인 규칙의 특별한 경우입니다. 짧은 기능은 이해하기 쉽고 디버그하기 쉬울뿐만 아니라 프로그램을보다 표현력있게 만드는 일종의 '단일 목적'디자인을 고수하는 데 더 좋습니다. main아마도 main코드베이스의 모호한 코너가 덜 자주 방문 할 수 있지만 프로그램을 이해하려는 사람은 이해해야하기 때문에 규칙을 고수하는 것이 더 중요한 장소 일 것 입니다.

그러나 파이썬 코드베이스는 Py_Main이 규칙을 적용하기 위해 코드를 푸시하지 않지만 main라이브러리에서 내보내 거나 함수로 호출 할 수 없기 때문에 .


-1

위의 몇 가지 기술적 답변이 있습니다.

메인은 부트 스트랩이어야하기 때문에 짧아야합니다. 메인은 작업을 수행하는 적은 수의 객체를 인스턴스화해야합니다. 다른 곳과 마찬가지로 이러한 객체는 잘 디자인되고 응집력 있고 느슨하게 결합되어 캡슐화되어 있어야합니다.

한 줄의 메인 콜에서 다른 몬스터 메소드를 사용해야하는 기술적 이유가있을 수 있지만 원칙적으로는 맞습니다. 소프트웨어 엔지니어링 관점에서, 아무것도 얻지 못했습니다. 선택이 괴물 방법을 호출하는 한 줄 메인과 괴물 방법을 메인으로 선택하는 경우 후자는 부분적으로 덜 나쁩니다.


"C ++ 코드는 객체를 사용해야하며 객체 만 사용해야한다"고 가정합니다. 사실 C ++은 다중 패러다임 언어이며 다른 언어와 마찬가지로 모든 것을 OO 금형으로 강요하지는 않습니다.
벤 Voigt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.