programing

C에서 글로벌 변수를 사용하는 것은 언제가 좋습니까?

bestcode 2022. 7. 16. 15:10
반응형

C에서 글로벌 변수를 사용하는 것은 언제가 좋습니까?

"절대 안 돼!"라는 다양한 의견이 있는 것 같아요. (단순한 매크로로라도) 항상 캡슐화해 주세요.」별것 아닙니다.편할사용합니다.」

그렇게.

구체적이고 구체적인 이유(가급적이면 예를 들어)

  • 글로벌 변수가 위험한 이유
  • 대체 변수 대신 전역 변수를 사용해야 하는 경우
  • 글로벌 변수를 부적절하게 사용하고 싶은 사용자를 위해 어떤 대안이 있는가?

이것은 주관적이지만, 저는 하나의 대답(모든 개발자가 글로벌에 대해 가져야 할 사랑과 증오의 관계를 가장 잘 나타낸다는 것)을 선택하고, 커뮤니티는 그들의 답변을 바로 아래에 투표할 것입니다.

신입사원에게는 이런 참고문헌이 중요하다고 생각합니다만, 자신과 실질적으로 비슷한 답변이 또 있다고 해서 혼란스럽게 하지 말아 주세요.댓글을 달거나 다른 사람의 답변을 편집해 주세요.

-아담

변수는 항상 가능한 한 작은 범위를 가져야 합니다.그 배경에는 범위를 늘릴 때마다 변수를 수정할 수 있는 코드가 많아지기 때문에 솔루션이 복잡해집니다.

따라서 설계와 구현이 자연스럽게 허용된다면 전역 변수 사용을 피하는 것이 바람직하다는 것은 분명하다.그렇기 때문에 글로벌 변수가 꼭 필요한 경우가 아니면 사용하지 않는 것이 좋습니다.

나 역시 '절대'라는 말에 동의할 수 없다.다른 개념과 마찬가지로 글로벌 변수는 필요할 때만 사용해야 합니다.본의만을 가리는 인위적인 구성(예를 들어 포인터 전달)을 사용하는 것보다 글로벌 변수를 사용하는 것이 좋습니다.

글로벌 변수가 사용되는 좋은 예로는 싱글톤 패턴 구현 또는 임베디드 시스템에서의 레지스터 액세스 등이 있습니다.

글로벌 변수의 과도한 사용을 실제로 검출하는 방법: 검사, 검사, 검사.글로벌 변수를 볼 때마다 다음과 같이 자문해야 합니다.그게 정말 전 세계적으로 필요한가요?

글로벌 변수를 작동시킬 수 있는 유일한 방법은 고유한 이름을 지정하는 것입니다.

이 이름에는 보통 글로벌 변수가 특히 집중되거나 의미가 있는 일부 "모듈" 또는 함수 집합과 관련된 접두사가 있습니다.

변수 '입니다.은 보통 작은 으로 " 수 . 같은 에서는 "랩핑"이 가능합니다..h파일명 프리픽스

보너스.

그렇게 하면 갑자기 더 이상 글로벌하지 않게 됩니다.이제 관련 기능의 일부 모듈의 일부입니다.

이것은 항상 할 수 있다.조금만 생각해 보면 이전의 모든 글로벌 변수를 특정 기능 모음에 할당하고 특정 기능에 할당할 수 있습니다..h파일, 그리고 변수를 중단하지 않고 변경할 수 있는 기능으로 격리됩니다.

"글로벌 변수를 절대 사용하지 않음"이라고 말하는 대신 "글로벌 변수의 책임을 가장 적합한 모듈에 할당"이라고 말할 수 있습니다.

C의 글로벌 변수는 변수를 각 메서드에 전달하는 것이 아니라 여러 메서드에 의해 변수가 필요한 경우 코드를 보다 쉽게 읽을 수 있도록 하는 데 유용합니다.그러나 모든 위치에는 변수를 수정할 수 있는 기능이 있어 버그를 추적하기가 어려울 수 있기 때문에 위험합니다.글로벌 변수를 사용해야 할 경우 반드시 한 가지 방법으로 직접 수정하고 다른 모든 발신자가 이 방식을 사용하도록 하십시오.이를 통해 해당 변수의 변경과 관련된 문제를 훨씬 쉽게 디버깅할 수 있습니다.

  • 사용하지 않는 경우: 글로벌 변수가 어떻게 변경되었는지 알 수 있는 유일한 방법은 글로벌 변수가 선언된 .c 파일(또는 외부인 경우 모든 .c 파일) 내에서 소스 코드 전체를 추적하는 것이기 때문에 글로벌 변수는 위험합니다.코드가 버그가 되면 소스 파일 전체를 검색하여 어떤 함수가 코드를 언제 변경하는지 확인해야 합니다.문제가 발생했을 때 디버깅하는 것은 악몽입니다.우리는 종종 지역 변수라는 개념의 이면에 있는 독창성을 당연하게 여깁니다.추적이 간단합니다.
  • 사용 시기: 글로벌 변수는 사용률이 과도하게 마스킹되지 않고 로컬 변수 사용 비용이 지나치게 복잡하여 가독성을 저해하는 경우에 사용해야 합니다.즉, 함수 인수나 반환, 포인터 전달 등에 파라미터를 추가할 필요가 있습니다.세 가지 전형적인 예:pop과 push stack을 사용하는 경우 기능 간에 공유됩니다.물론 로컬 변수를 사용할 수 있지만 추가 파라미터로 포인터를 전달해야 합니다.두 번째 고전적인 예는 K&R의 "The C Programming Language"에서 찾을 수 있습니다.여기서 글로벌 문자 버퍼 배열을 공유하는 getch() 함수 및 ungetch() 함수를 정의합니다.다시 한 번 말씀드리지만, 버퍼 사용을 망치기 어려운 상황에서 복잡성이 가중되는 것이 가치가 있을까요?세 번째 예는 Arduino의 애호가들에게서 찾을 수 있는 것입니다.메인 루프 함수 내의 많은 함수는 모두 함수를 호출한 순간 시간인 millis() 함수를 공유합니다.클럭 속도는 무한하지 않기 때문에 millis()는 단일 루프 내에서 다릅니다.일정하게 하려면 각 루프 전에 시간의 스냅샷을 생성하여 글로벌 변수에 저장합니다.이제 시간 스냅샷은 여러 함수로 액세스할 때와 동일합니다.
  • 다른 방법:많지 않다.가능한 한 로컬 범위를 고수합니다.특히 프로젝트 시작 부분에서는 로컬 범위를 고수하지 마십시오.프로젝트가 확장되고 글로벌 변수를 사용하여 복잡성을 줄일 수 있다고 생각되는 경우 두 번째 포인트의 요건을 충족하는 경우에만 그렇게 하십시오.또한 로컬 스코프를 사용하고 보다 복잡한 코드를 갖는 것이 글로벌 변수를 무책임하게 사용하는 것에 비해 덜 나쁜 일입니다.

스레드 세이프 코드가 걱정되지 않는 경우: 의미 있는 곳, 즉 글로벌한 상태로 표현하기 위해 의미 있는 곳이라면 어디에나 사용하십시오.

코드가 멀티 스레드인 경우: 반드시 피하십시오.글로벌 변수를 작업 큐 또는 기타 스레드 세이프 구조로 추상화하거나, 꼭 필요한 경우 프로그램 내 병목현상이 될 수 있다는 점에 유의하십시오.

코드의 복잡성만이 문제의 최적화는 아닙니다.많은 애플리케이션에서 성능 최적화는 훨씬 더 높은 우선 순위를 가집니다.그러나 더 중요한 것은 글로벌 변수를 사용하면 많은 상황에서 코드 복잡성을 크게 줄일 수 있다는 것입니다.글로벌 변수가 수용 가능한 솔루션일 뿐만 아니라 선호되는 상황도 많이 있습니다.제가 가장 좋아하는 특수한 예는 실시간 스레드에서 실행되는 오디오 콜백 기능을 사용하여 응용 프로그램의 메인 스레드 간에 통신을 제공하는 것입니다.

여러 스레드에서 변경에 노출될 경우 범위에 관계없이 모든 변수가 잠재적 위험이 되므로 글로벌 변수가 멀티 스레드 애플리케이션에서 위험하다고 제안하는 것은 잘못된 것입니다.

글로벌 변수는 신중하게 사용합니다.가능한 한 데이터 구조를 사용하여 글로벌 네임스페이스를 구성하고 분리해야 합니다.

가변 범위는 프로그래머에게 매우 유용한 보호를 제공하지만 비용이 들 수 있습니다.저는 Objective-C의 경험이 풍부한 프로그래머이기 때문에 오늘 밤 글로벌 변수에 대해 글을 쓰게 되었습니다.데이터 액세스의 객체 지향성에 대한 장벽에 자주 좌절합니다.반세계적 광신도는 주로 객체 지향 API를 단독으로 경험하고 응용 프로그램 개발에서 그들의 상호작용에 대한 깊고 실용적인 경험 없이 이론적으로 진보된 젊은 프로그래머들로부터 나온다고 나는 주장한다.하지만 공급업체가 네임스페이스를 함부로 사용할 경우 좌절감을 느낀다는 것은 인정해야 합니다.예를 들어, 몇몇 Linux Distros는 "PI"와 "TWOPI"가 세계적으로 미리 정의되어 있어 개인 코드의 많은 부분이 깨졌습니다.

저는 우리 회사에 엣지 케이스가 있다고 생각합니다.그 때문에, 「글로벌 변수를 사용하지 않는 캠프」에 들어갈 수 없게 되었습니다.

병원 내 장치에서 의료 데이터를 가져오는 임베디드 어플리케이션을 작성해야 합니다.

이 기능은 의료 기기가 꺼져 있거나 네트워크가 끊어지거나 박스 설정이 변경되어도 무한히 실행됩니다.설정은 .txt 파일에서 읽을 수 있으며, 실행 시 문제 없이 변경할 수 있습니다.

그래서 싱글톤 패턴은 나에게 쓸모가 없다.따라서 (1000개의 데이터를 읽은 후) 때때로 이전으로 돌아가서 다음과 같은 설정을 읽습니다.

public static SettingForIncubator settings;

public static void main(String[] args) {
    while(true){
        SettingsForIncubator settings = getSettings(args);

        int counter=0;

        while(medicalDeviceIsGivingData && counter < 1000){
            readData(); //using settings

            //a lot of of other functions that use settings.

            counter++;
        }
    } 
}

「범위가 좁으면, 모든 것이 글로벌하다」라고 하는 코안을 생각해 주세요.

이 시대에도 한 번뿐인 작업을 하기 위해 매우 빠른 유틸리티 프로그램을 작성해야 하는 것은 매우 가능합니다.

이러한 경우 변수에 대한 안전한 접근을 생성하기 위해 필요한 에너지는 이러한 소규모 유틸리티에서 문제를 디버깅하여 절약하는 에너지보다 큽니다.

글로벌 변수가 현명한 경우라고 즉석에서 생각할 수 있는 유일한 경우이며, 비교적 드문 경우입니다.유용하고, 너무 작아서 뇌의 단기 기억 안에 완전히 저장될 수 있는 새로운 프로그램들은 점점 더 드물지만, 여전히 존재한다.

사실, 이 프로그램이 이렇게 작지 않다면, 글로벌 변수는 불법이 되어야 한다고 과감하게 주장할 수 있습니다.

  • 변수가 변경되지 않으면 변수가 아니라 상수입니다.
  • 변수가 유니버설액세스를 필요로 하는 경우 변수를 가져오고 설정하기 위한2개의 서브루틴이 존재해야 합니다.이러한 서브루틴은 동기화되어 있어야 합니다.
  • 프로그램이 작게 시작하여 나중에 커질 수 있는 경우에는 프로그램이 큰 것처럼 코드화하고 글로벌 변수를 폐지합니다.모든 프로그램이 확장되는 것은 아닙니다!(물론 프로그래머가 때때로 코드를 폐기하는 것을 전제로 하고 있습니다.)

저는 '절대' 캠프에 있습니다.글로벌 변수가 필요하다면 적어도 싱글톤 패턴을 사용하세요.이렇게 하면 느린 인스턴스화의 이점을 얻을 수 있고 글로벌 네임스페이스를 복잡하게 만들지 않아도 됩니다.

나는 방위산업에 종사하기 전까지 "절대" 캠프에서 왔다.업계 표준 중에는 소프트웨어가 다이내믹(C 케이스의 malloc) 메모리 대신 글로벌 변수를 사용해야 하는 것도 있습니다.현재 작업 중인 일부 프로젝트에서 동적 메모리 할당에 대한 접근 방식을 재고해야 합니다.적절한 세마포나 스레드 등을 사용하여 "글로벌" 메모리를 보호할 수 있다면 메모리 관리에 적합한 접근법이 될 수 있습니다.

글로벌 변수를 어떤 컨텍스트에서 사용하는지도 고려해야 합니다.앞으로 이 코드를 복제하시겠습니까?

예를 들어 시스템 내의 소켓을 사용하여 리소스에 액세스하는 경우입니다.향후, 이러한 자원 중 하나 이상을 액세스 하고 싶다고 생각하고 있습니다.그렇다고 대답할 경우, 저는 애초에 글로벌에서 떨어져 있기 때문에, 메이저리팩터가 필요 없습니다.

그것은 보통 과도하게 사용되는 다른 도구들과 같은 도구이지만 나는 그것들이 나쁘다고 생각하지 않는다.

예를 들어 온라인 데이터베이스와 같은 기능을 하는 프로그램이 있습니다.데이터는 메모리에 저장되지만 다른 프로그램이 데이터를 조작할 수 있습니다.데이터베이스의 저장 프로시저 및 트리거와 매우 유사한 내부 루틴이 있습니다.

이 프로그램은 수백 개의 글로벌 변수를 가지고 있지만, 생각해보면 데이터베이스이지만 엄청난 수의 글로벌 변수를 가지고 있습니다.

이 프로그램은 지금까지 약 10년 동안 많은 버전을 통해 사용되어 왔으며, 지금까지 문제가 된 적이 없으며 잠시 후에 다시 사용하겠습니다.

이 경우 글로벌 변수들은 객체의 상태를 변경하기 위해 사용되는 메서드를 가진 객체임을 인정한다.따라서 디버깅 중에 개체를 변경한 사용자를 추적하는 것은 문제가 되지 않습니다. 왜냐하면 개체의 상태를 변경하는 루틴에 중단점을 항상 설정할 수 있기 때문입니다.또는 변경을 기록하는 내장 로그를 켜기만 하면 됩니다.

글로벌 변수는 여러 함수가 데이터에 액세스하거나 개체에 써야 할 때 사용해야 합니다.예를 들어 단일 로그 파일, 연결 풀 또는 애플리케이션 전체에서 액세스해야 하는 하드웨어 참조와 같은 여러 기능에 대한 데이터 또는 참조를 전달해야 하는 경우입니다.이렇게 하면 함수 선언이 매우 길어지고 중복된 데이터가 대량으로 할당되는 것을 방지할 수 있습니다.

절대적 필요할 때 명시적으로 그렇게 하는 것이나 당신의 프로그램이 종료됬다고 글로벌 변수만 청소한다고 일반적으로 세계적인 변수를 사용하지 않아야 한다.만약 당신이 돌아가는 멀티 스레드 응용 프로그램 실행하고 있고 여러가지 기능 변수로의 동시에 쓸 수 있다.만약 당신이 있는 기능은 변수 변화하고 있는지 모르는 곤충 벌레, 추적 더 어렵게 될 수 있다.또한지 못하는 한 명시적으로 세계적인 변수는 독특한 이름을 명명 규칙을 사용한다 갈등에 이름을 붙인 것의 그 문제에 부딪힌다.

상수를 선언하는 경우.

몇 가지 이유를 생각할 수 있습니다.

디버깅/디버깅 목적(경고 - 이 코드를 테스트하지 않았습니다):

#include <stdio.h>
#define MAX_INPUT 46
int runs=0;
int fib1(int n){
    ++runs;
    return n>2?fib1(n-1)+fib1(n-2):1;
};
int fib2(int n,int *cache,int *len){
    ++runs;
    if(n<=2){
        if(*len==2)
            return 1;
        *len=2;
        return cache[0]=cache[1]=1;
    }else if(*len>=n)
        return cache[n-1];
    else{
        if(*len!=n-1)
            fib2(n-1,cache,len);
        *len=n;
        return cache[n-1]=cache[n-2]+cache[n-3];
    };
};
int main(){
    int n;
    int cache[MAX_INPUT];
    int len=0;
    scanf("%i",&n);
    if(!n||n>MAX_INPUT)
        return 0;
    printf("fib1(%i)==%i",n,fib1(n));
    printf(", %i run(s)\n",runs);
    runs=0;
    printf("fib2(%i)==%i",n,fib2(n,&cache,&len));
    printf(", %i run(s)\n",runs);
    main();
};

fib2에 스코프 변수를 사용했지만, 글로벌이 유용할 수 있는 시나리오(영원히 오래 걸리지 않도록 데이터를 저장해야 하는 순수 수학 함수)가 하나 더 있습니다.

(예를 들어 콘테스트를 위해) 한 번만 사용되는 프로그램 또는 개발 시간을 단축해야 할 때

globals는 입력된 상수로 유용합니다. 여기서 함수는 int 대신 *int를 필요로 합니다.

저는 보통 하루 이상 프로그램을 사용할 예정이라면 글로벌은 피합니다.

글로벌 상수는 편리합니다.프리프로세서 매크로보다 타입의 안전성이 높고, 필요에 따라서 값을 변경하는 것도 간단합니다.

예를 들어 프로그램의 많은 부분의 동작이 상태 시스템의 특정 상태에 따라 달라지는 경우 등 글로벌 변수는 몇 가지 용도가 있습니다.변수 추적 버그를 수정할 수 있는 장소의 수를 제한하기만 하면 나쁘지 않습니다.

글로벌 변수는 여러 스레드를 작성하는 즉시 위험해집니다.이 경우 스코프를 (스태틱하다고 선언함으로써) 파일 전역 변수 및 위험할 수 있는 다중 액세스로부터 보호하는 getter/setter 메서드로 제한해야 합니다.

언급URL : https://stackoverflow.com/questions/176118/when-is-it-ok-to-use-a-global-variable-in-c

반응형