C / C ++에서 교수님이 생각하는 것만 큼 전역 변수가 나쁜가요?
C / C ++에서 교수님이 생각하는 것만 큼 전역 변수가 나쁜가요?
답변:
전역 변수의 문제점은 모든 함수가 이들에 액세스 할 수 있기 때문에 실제로 어떤 변수가 이러한 변수를 읽고 쓰는지 파악하기가 점점 더 어려워진다는 것입니다.
응용 프로그램의 작동 방식을 이해하려면 전역 상태를 수정하는 모든 기능을 고려해야합니다. 그렇게 할 수는 있지만 응용 프로그램이 성장함에 따라 사실상 불가능한 시점 (또는 적어도 완전한 시간 낭비)까지 어려워 질 것입니다.
전역 변수에 의존하지 않는 경우 필요에 따라 다른 함수간에 상태를 전달할 수 있습니다. 이렇게하면 전역 상태를 고려할 필요가 없으므로 각 기능의 기능을 이해하는 데 훨씬 유리합니다.
중요한 것은 전반적인 목표를 기억하는 것입니다 : 명확성
"전역 변수 없음"규칙은 대부분의 경우 전역 변수가 코드의 의미를 덜 명확하게하기 때문에 존재합니다.
그러나 많은 규칙과 마찬가지로 사람들은 규칙을 기억하지만 규칙의 의도가 아닙니다.
전역 변수의 악을 피하기 위해 엄청난 수의 매개 변수를 전달하여 코드 크기를 두 배로 늘리는 프로그램을 보았습니다. 결국, 전역을 사용하면 프로그램 을 읽는 사람들에게 프로그램이 더 명확 해졌 습니다. 원래의 프로그래머는 규칙의 말을 무심코 고수함으로써 규칙의 의도에 실패했다.
그렇습니다. 세계는 종종 나쁩니다. 그러나 결국 전역 변수를 사용하여 프로그래머의 의도가 더 명확하다고 생각되면 계속 진행하십시오. 그러나 누군가가 두 번째 코드 (전역)에 액세스하여 첫 번째 코드의 작동 방식을 이해하도록하면 자동으로 명확성이 떨어집니다.
교수님은 다음과 같이 말씀하셨습니다. 전역 변수를 올바르게 사용하면 괜찮습니다. 나는 그것들을 올바르게 사용하는 데 능숙하다고 생각하지 않으므로 거의 사용하지 않습니다.
static
전역 변수를 많이 사용하고 언어는 C입니다. 상대적으로 작은 번역 단위에 국한되어 C ++ 객체의 클래스 변수와 비슷해지기 시작합니다.
program lifetime, file scope variables
. 그리고 변수에 대한 포인터를 외부 세계에
static
전역 변수는 범위가 동일한 번역 단위로 제한됩니다. 그러나 그들은 글로벌 변수로서 프로그램이 끝날 때까지 평생 있습니다.
전역 변수는 대안이없는 경우에만 사용해야합니다. 그렇습니다. 여기에는 싱글 톤이 포함됩니다. 90 %의 시간 동안 전역 변수가 도입되어 매개 변수를 전달하는 비용을 절약합니다. 그런 다음 멀티 스레딩 / 유닛 테스트 / 유지 보수 코딩이 발생하며 문제가 있습니다.
그렇습니다. 90 %의 상황에서 전역 변수는 나쁩니다. 대학 시절에는 예외가 보이지 않을 것입니다. 내 머리 꼭대기에서 생각할 수있는 한 가지 예외는 인터럽트 테이블과 같은 본질적으로 전역 객체를 처리하는 것입니다. DB 연결과 같은 것은 세계적인 것처럼 보이지만 그렇지 않습니다.
전역 변수가 프로그래머에게 생성하는 문제는 전역 변수를 사용 하는 다양한 구성 요소 사이에서 구성 요소 간 결합 표면을 확장한다는 것 입니다. 이것이 의미하는 것은 전역 변수를 사용하는 구성 요소의 수가 증가함에 따라 상호 작용의 복잡성도 증가 할 수 있다는 것입니다. 이 증가 된 커플 링은 일반적으로 변경시 결함을 시스템에 주입하기 쉽고 결함을 진단하고 수정하기 어렵게합니다. 이 증가 커플 링은 또한 변경을 수행 할 때 사용 가능한 옵션 수를 줄일 수 있으며 변경 결과를 판별하기 위해 전역 변수를 사용하는 다양한 모듈을 추적해야하는 경우 변경에 필요한 노력을 증가시킬 수 있습니다.
기본적으로 전역 변수를 사용하는 것과 반대되는 캡슐화 의 목적은 소스를 이해하고 변경하기 쉽고 안전하고 쉽게 테스트 할 수 있도록 커플 링을 줄이는 것입니다. 전역 변수를 사용하지 않을 때 단위 테스트 를 사용하는 것이 훨씬 쉽습니다 .
예를 들어, 다양한 구성 요소가 상태 머신으로 사용되는 열거 된 표시기로 사용되는 단순 전역 정수 변수가 있고 새 구성 요소에 새 상태를 추가하여 변경 한 경우 다른 모든 구성 요소를 추적해야합니다. 변경 사항이 변경 사항에 영향을 미치지 않도록합니다. 가능한 현재 문제점의 예는 현재 값 각각에 대한 명령문으로 switch
열거 글로벌 변수의 값을 테스트하기 case
위한 명령문이 다양한 위치에서 사용되고 있으며, switch
명령문 중 일부 default
가 처리 할 경우 가없는 경우입니다. 응용 프로그램과 관련하여 갑자기 정의되지 않은 동작이 발생할 수 있습니다.
반면에 공유 데이터 영역을 사용하면 응용 프로그램 전체에서 참조되는 전역 매개 변수 집합을 포함 할 수 있습니다. 이 방법은 메모리 공간이 작은 임베디드 응용 프로그램에서 종종 사용됩니다.
이러한 종류의 응용 프로그램에서 전역 변수를 사용하는 경우 일반적으로 데이터 영역에 쓰는 책임은 단일 구성 요소에 할당되며 다른 모든 구성 요소는 해당 영역을 const
읽거나 읽지 않고 해당 영역을 읽습니다. 이 방법을 사용하면 발생할 수있는 문제가 제한됩니다.
해결해야 할 전역 변수의 몇 가지 문제
구조체와 같은 전역 변수의 소스가 수정되면 변수를 사용하는 모든 것이 실제 크기와 메모리 템플릿을 알 수 있도록이를 사용하는 모든 것을 다시 컴파일해야합니다.
둘 이상의 구성 요소가 글로 z 변수를 수정할 수있는 경우 글로 z 변수에 일관되지 않은 데이터가있는 데 문제가 생길 수 있습니다. 멀티 스레딩 응용 프로그램을 사용하면 한 번에 하나의 스레드 만 전역 변수를 수정할 수 있고 스레드가 변수를 수정하는 경우 모든 변경이 완료 될 수 있도록 일종의 잠금 또는 임계 영역을 추가해야 할 수 있습니다. 다른 스레드가 변수를 쿼리하거나 수정하기 전에 커밋됩니다.
전역 변수를 사용하는 다중 스레드 응용 프로그램을 디버깅하는 것이 더 어려울 수 있습니다. 복제하기 어려운 결함을 생성 할 수있는 경쟁 조건 에 처할 수 있습니다. 여러 개의 컴포넌트, 특히 다중 스레드 응용 프로그램에서 전역 변수를 통해 통신하는 경우, 컴포넌트가 변수를 변경하는시기와 변수를 변경하는 구성 요소를 이해하기가 매우 어려울 수 있습니다.
전역 변수 사용시 이름 충돌이 문제가 될 수 있습니다. 글로벌 변수와 이름이 같은 로컬 변수는 글로벌 변수를 숨길 수 있습니다. 또한 C 프로그래밍 언어를 사용할 때 명명 규칙 문제가 발생합니다. 해결 방법은 시스템을 특정 하위 시스템에 대한 전역 변수를 사용하여 동일한 처음 세 글자로 시작하는 하위 시스템으로 나누는 것입니다 ( 목표 C에서 네임 스페이스 충돌 해결 에 대한 내용 참조 ). C ++는 네임 스페이스를 제공하며 C를 사용하면 멤버가 다양한 데이터 항목이며 파일에 정적 포인터로 제공되는 데이터 및 함수에 대한 포인터 인 전역 적으로 볼 수있는 구조체를 작성하여이를 해결할 수 있습니다. 세계적으로 보이는 구조체.
경우에 따라 원래 응용 프로그램 의도가 변경되어 단일 스레드에 대한 상태를 제공 한 전역 변수가 여러 개의 중복 스레드를 실행할 수 있도록 수정됩니다. 예를 들어 상태에 대한 전역 변수를 사용하여 단일 사용자를 위해 설계된 간단한 응용 프로그램이 있고 원격 응용 프로그램이 가상 사용자로 작동 할 수 있도록 REST 인터페이스 를 추가하라는 요청이 관리에서 발생 합니다. 이제 전역 변수와 상태 정보를 복제해야하므로 단일 사용자와 원격 응용 프로그램의 각 가상 사용자가 고유하고 고유 한 전역 변수 세트를 갖도록해야합니다.
C ++ namespace
및 struct
C 기법 사용
C ++ 프로그래밍 언어의 경우 namespace
지시문은 이름 충돌 가능성을 줄이는 데 큰 도움이됩니다. namespace
와 함께 class
다양한 액세스 키워드 ( private
, protected
및 public
)는 변수를 캡슐화하는 데 필요한 대부분의 도구를 제공합니다. 그러나 C 프로그래밍 언어는이 지시어를 제공하지 않습니다. 이 스택 오버 플로우 게시 인 Namespaces in C는 C 에 대한 몇 가지 기술을 제공합니다.
유용한 기술은 struct
전역 가시성을 갖는 것으로 정의 된 단일 메모리 상주 데이터 영역을 갖는 것이며, 여기에는 struct
노출되는 다양한 전역 변수 및 함수에 대한 포인터가 있습니다. 글로벌 변수의 실제 정의는 static
키워드를 사용하여 파일 범위에 제공됩니다 . 그런 다음 const
키워드를 사용하여 읽기 전용을 나타내는 경우, 컴파일러는 읽기 전용 액세스를 시행하도록 도울 수 있습니다.
이 struct
기술을 사용하면 전역을 캡슐화하여 전역이되는 일종의 패키지 또는 구성 요소가 될 수 있습니다. 이러한 종류의 구성 요소를 사용하면 전역을 사용하여 전역 및 기능에 영향을주는 변경 사항을 관리하기가 쉬워집니다.
그러나 namespace
또는 struct
기술이 이름 충돌을 관리하는 데 도움이 될 수는 있지만 특히 최신 멀티 스레드 응용 프로그램에서 전역을 사용할 때 발생하는 구성 요소 간 연결의 근본적인 문제는 여전히 존재합니다.
대법원 재판 중에 코드가 집중 검토 될 가능성이 있다면 전역 변수를 피하고 싶을 것입니다.
이 문서를 참조하십시오 : 버기 음주 측정기 코드 소스 검토의 중요성을 반영
두 연구에서 확인한 코드 스타일에 문제가있었습니다. 검토 자와 관련된 문체 문제 중 하나는 보호되지 않은 전역 변수 의 광범위한 사용이었습니다 . 이는 프로그램 상태가 일치하지 않거나 값이 실수로 수정되거나 덮어 쓰기 될 위험이 높아지기 때문에 잘못된 형식으로 간주됩니다. 연구원들은 십진 정밀도가 코드 전체에서 일관되게 유지되지 않는다는 사실에 대해 우려를 표명했습니다.
남자, 나는 그 개발자들이 전역 변수를 사용하지 않기를 바랐다.
전역 변수는 변수를 만드는만큼 나쁘지 않습니다.
완전히 캡슐화 된 프로그램을 작성중인 경우 전역을 사용할 수 있습니다. 전역을 사용하는 것은 "죄"이지만 프로그래밍 죄는 매우 철학적입니다.
L.in.oleum 을 확인하면 변수가 전적으로 전역 인 언어가 표시됩니다. 라이브러리는 모두 전역을 사용하는 것 외에는 선택의 여지가 없기 때문에 확장 할 수 없습니다.
즉, 선택의 여지가 있고 프로그래머의 철학을 무시할 수 있다면 글로벌 세계가 그렇게 나쁘지는 않습니다.
올바르게 사용하면 Goto도 마찬가지입니다.
큰 "나쁜"문제는 당신이 잘못 사용하면 사람들이 비명을 지르고 화성 착륙선이 추락하며 세상이 터져 버린다는 것입니다.
나는이 질문에 또 다른 질문으로 대답 할 것입니다 : 당신은 singeltons 를 사용 합니까 / singeltons는 나쁜가?
(거의 모든) singelton 사용법은 영광스러운 전역 변수이기 때문입니다.
문제는 그들이 나쁘다 는 것보다 적고 , 더 위험하다는 것 입니다. 그들에게는 장단점이 있으며 특정 작업을 수행하는 가장 효율적이거나 유일한 방법 인 상황이 있습니다. 그러나, 그들은있어 매우 당신이 항상 적절하게 사용하기위한 조치를 취할 경우에도, 오용에 편리합니다.
몇 가지 장점 :
몇 가지 단점 :
만일 당신이 원한다면, 내가 처음 두 장단점과 처음 두 장단점은 다른 말로 똑같은 것입니다. 전역 변수의 기능은 실제로 유용 할 수 있지만,이를 유용하게 만드는 기능은 모든 문제의 원인입니다.
몇 가지 문제에 대한 몇 가지 잠재적 인 해결책 :
Globals
또는 GlobalVars
) 으로 네임 스페이스 [C ++] 또는 싱글 톤 구조체 [C, C ++] 에 넣거나 전역 변수에 대해 표준화 된 명명 규칙 (예 : global_[name]
또는 g_module_varNameStyle
underscore_d로 언급)을 사용하십시오. )). 이것은 사용법을 문서화하고 (네임 스페이스 / 구조 명을 검색하여 글로벌 변수를 사용하는 코드를 찾을 수 있음) 글로벌 네임 스페이스에 미치는 영향을 최소화합니다.extern
에 넣고 관련 헤더에 선언하면 액세스가 필요한 컴파일 단위로 제한 될 수 있습니다. 코드가 많은 전역 변수에 의존하지만 각 컴파일 단위가 소수의 변수에만 액세스해야하는 경우 여러 소스 파일로 정렬하는 것을 고려할 수 있으므로 각 파일의 전역 변수 액세스를보다 쉽게 제한 할 수 있습니다.그들이 좋은지 나쁜지는 사용 방법에 달려 있습니다. 대다수는 그것들을 잘못 사용하는 경향이 있으며, 따라서 그들에 대한 일반적인주의. 올바르게 사용하면 큰 이익이 될 수 있습니다. 잘못 사용 된 경우, 그러나, 그들은 할 수 있습니다 것입니다 당신을 다시 물어 올 때 당신은 적어도 그것을 기대하는 방법.
그것을 보는 좋은 방법은 그들 자체가 나쁘지는 않지만 나쁜 디자인을 가능하게하고 나쁜 디자인의 효과를 기하 급수적으로 증가시킬 수 있다는 것입니다.
사용하지 않더라도 안전하게 사용하는 방법을 모르기 때문에 사용하지 않는 것보다 안전하게 사용하는 방법을 알고 사용하지 않는 것이 좋습니다. 전역 변수에 의존하는 기존 코드를 유지해야하는 상황에 처한 경우 올바르게 사용하는 방법을 모르면 어려움을 겪을 수 있습니다.
g_module_varNameStyle
완벽하게 읽기. 분명히, 나는 쉽게 키워드를 쉽게 피할 수 있다면 글로벌을 사용하지 않습니다 . 왜냐하면 모든 비용을 피해야하거나 헷갈 리게 해야한다고 믿지 않기 때문에 훨씬 나은 시간을 보내고 있습니다. 코드는 (충격입니다!) 훨씬 더 깔끔한
다른 스레드에서 누군가가 말했듯이 (나는 역설적이다) "이러한 규칙의 결과를 완전히 이해하기 전까지는 이와 같은 규칙을 어 기지 말아야한다."
전역 변수가 필요하거나 최소한 매우 유용한 경우가 있습니다 (예 : 시스템 정의 콜백 작업). 반면에, 그들은 당신이 들었던 모든 이유로 인해 매우 위험합니다.
전문가에게 맡겨야 할 프로그래밍에는 여러 가지 측면이 있습니다. 때때로 당신은 매우 날카로운 칼이 필요합니다. 그러나 준비가 될 때까지는 사용할 수 없습니다.
전역 변수를 사용하는 것은 깔개 밑의 흙을 쓸어 버리는 것과 같습니다. 먼지를 제거하거나 진공 청소기로 청소하는 것보다 빠른 해결 방법이며 단기적으로 훨씬 쉽습니다. 그러나 나중에 깔개를 움직 인 후에는 큰 놀라움이 생길 것입니다.
절대적으로하지. 그래도 잘못 사용하는 것은 좋지 않습니다.
무심코 그들을 위해 그들을 제거하는 것은 단지 ... 마음이 없습니다. 당신이 advanatages와 단점을 알지 않는 한, 당신이 가르치고 배우는 것처럼 명확하고 행동하는 것이 가장 좋지만 전역 변수에는 암묵적으로 잘못된 것은 없습니다. 장단점을 이해하면 더 나은 결정을 내릴 수 있습니다.
전혀 나쁘지 않습니다. 이 결정을 내리기 위해 컴파일러가 생성 한 (기계) 코드를 살펴 봐야합니다. 때로는 전역보다 로컬을 사용하는 것이 훨씬 나쁩니다. 또한 로컬 변수에 "정적"을 적용하면 기본적으로 전역 변수가됩니다 (실제 전역 변수로 해결할 수있는 다른 추악한 문제가 발생 함). "지역 글로벌"은 특히 나쁘다.
Globals는 메모리 사용량을 깔끔하게 제어 할 수있게 해줍니다. 요즘에는 메모리가 상당히 제한된 임베디드 환경에서만 중요합니다. 임베디드가 다른 환경과 동일하다고 가정하고 프로그래밍 규칙이 전반적으로 동일하다고 가정하기 전에 알아야 할 사항.
가르치는 규칙에 의문을 갖는 것이 좋으며, 대부분의 규칙은 당신이 말하는 이유가 아닙니다. 그러나 가장 중요한 교훈은 이것이 당신을 영원히 가지고 다니는 규칙이라는 것이 아니라, 이것은이 수업을 통과하고 앞으로 나아 가기 위해 명예롭게하는 규칙입니다. 실제로 XYZ 회사의 경우 월급을 계속 받으려면 결국 다른 프로그래밍 규칙을 준수해야합니다. 두 가지 상황 모두에서 규칙을 논쟁 할 수는 있지만 학교보다 직장에서 훨씬 더 운이 좋을 것이라고 생각합니다. 당신은 많은 학생들의 또 하나이고, 자리는 곧 교체 될 것입니다. 교수진은 당신이이 제품을 끝까지보아야하는 환경에서 개발 된 규칙이 제품과 회사뿐만 아니라 팀원의 이익 따라서 모든 사람들이 마음에 들거나 특정 제품의 경우 대학에서 배운 것을 일반 프로그래밍에 대해 위반 한 좋은 엔지니어링 이유가 있다면 아이디어를 팀에 팔아 선호하는 방법이 아닌 경우 유효한 것으로 적어 둡니다 . 모든 것이 현실 세계에서 공정한 게임입니다.
학교 나 책에서 배운 모든 프로그래밍 규칙을 준수하면 프로그래밍 경력이 극도로 제한됩니다. 당신은 생존하고 유익한 직업을 가질 수 있지만, 당신이 이용할 수있는 환경의 폭과 폭은 극도로 제한 될 것입니다. 규칙이 어떻게 그리고 왜 존재하는지 알고 그것을 방어 할 수 있다면, 그 이유는 단지 "선생님이 그렇게 말했기 때문"이라면 좋지 않습니다.
이와 같은 주제는 종종 직장에서 논쟁 중이며 컴파일러와 프로세서 (및 언어)가 이러한 종류의 규칙을 따르고 자신의 입장을 지키지 않고 다른 의견을 가진 사람에게 교훈을 얻지 않고 계속 발전함에 따라 계속 될 것입니다. 앞으로 움직이다.
그동안 가장 큰 소리를 내거나 가장 큰 지팡이를 들고있는 사람이 말하는대로 무엇이든하십시오.
이 스레드 전체에서 멀티 스레딩을 어렵게 만들거나 불가능하게 만드는 요점에 반대하고 싶습니다. 전역 변수는 공유 상태이지만 전역에 대한 대안 (예 : 포인터 전달)도 상태를 공유 할 수 있습니다. 멀티 스레딩의 문제점은 해당 상태가 전역 변수 또는 다른 것을 통해 공유되는지 여부가 아니라 공유 상태를 올바르게 사용하는 방법입니다.
멀티 스레딩을 할 때는 대부분 무언가를 공유해야합니다. 예를 들어 생산자-소비자 패턴에서 작업 단위가 포함 된 스레드 안전 큐를 공유 할 수 있습니다. 그리고 데이터 구조는 스레드로부터 안전하기 때문에 공유 할 수 있습니다. 스레드 안전성과 관련하여 해당 큐가 전역인지 여부는 전혀 관련이 없습니다.
전역을 사용하지 않을 때 프로그램을 단일 스레드에서 다중 스레드로 변환하는 것이 더 쉬울 것이라는이 스레드 전체에서 암시 된 희망은 순진합니다. 그렇습니다. 전 세계 사람들이 발을 쉽게 쏠 수는 있지만 자신을 쏠 수있는 방법이 많이 있습니다.
나는 다른 점이 여전히 서 있기 때문에 전역을 옹호하지는 않지만, 내 요점은 단지 프로그램의 스레드 수가 변수 범위와 관련이 없다는 것입니다.
보안이 적다는 것은 변수가 전역으로 선언 된 경우 변수를 조작 할 수 있음을 의미합니다.이 프로그램은 은행 프로그램에서 전역 변수로 균형이있는 경우이 예제를 설명합니다. 사용자 기능은 이것을 조작 할 수 있으며 은행 담당자는 조작 할 수도 있습니다 이것은 문제가 있습니다. 단지 사용자에게는 읽기 전용 및 인출 기능이 제공되어야하지만 은행 직원은 사용자가 책상에 현금을 개인적으로 줄 때 금액을 추가 할 수 있습니다.
다중 스레드 응용 프로그램에서는 경쟁 조건을 피하기 위해 전역 변수 대신 로컬 변수를 사용하십시오.
경쟁 조건은 여러 스레드가 공유 리소스에 액세스 할 때 발생하며 하나 이상의 스레드가 데이터에 대한 쓰기 액세스 권한을 갖습니다. 그런 다음 프로그램 결과를 예측할 수 없으며 다른 스레드에 의한 데이터 액세스 순서에 따라 다릅니다.