전역변수에 어울리는 변수는??

superkkt의 이미지

전역변수를 남발해서 사용하는건 좋지 않은 습관이라고 들었습니다. 그래서 최대한 전역변수 사용을 자제하려고 하는데요,..

지금 짜고 있는 프로그램이 제가 내공이 딸려서 그런건지는 모르겠지만 대부분의 변수가 전역변수로 사용되야지만 프로그램이 간결해지는것 같습니다.

체크를 해보니 예를들어 a라는 변수는 2~3개 이상의 함수가 참조를 합니다. 이정도면 a라는 변수는 전역변수로 선언해도 좋은가요?

흠.. 어떤 기준이 있다면 이렇게 머리가 안아플텐데요.. 예를들어 몇개 이상의 함수가 참조를 하면 전역변수로 사용하는게 좋다던지.,. 뭐 이런 기준들이요.. :cry:

File attachments: 
첨부파일 크기
Binary Data advent.pdf.gz595.54 KB

댓글

송효진의 이미지

전역변수를 쓰지 않는 방법으로 클래스의 사용은 어떤가요?

많은 변수의 사용이 필요한 경우, 리턴값도 2가지 이상의 값이 필요해질 경우가 많더라고요.

그래서 아예 클래스로 만들고 this->변수 로 해결하니,
리턴은 true/false 만 넘기게 되고,
예외처리하기도 좋고,
코딩 상태가 보기 좋던데요.

superkkt의 이미지

이제 C 배우기 시작한 초보라서 C++은 아직 엄두를 못내고 있습니다. :oops:

======================
BLOG : http://superkkt.com

익명 사용자의 이미지

superkkt wrote:
전역변수를 남발해서 사용하는건 좋지 않은 습관이라고 들었습니다. 그래서 최대한 전역변수 사용을 자제하려고 하는데요,..

지금 짜고 있는 프로그램이 제가 내공이 딸려서 그런건지는 모르겠지만 대부분의 변수가 전역변수로 사용되야지만 프로그램이 간결해지는것 같습니다.

체크를 해보니 예를들어 a라는 변수는 2~3개 이상의 함수가 참조를 합니다. 이정도면 a라는 변수는 전역변수로 선언해도 좋은가요?

흠.. 어떤 기준이 있다면 이렇게 머리가 안아플텐데요.. 예를들어 몇개 이상의 함수가 참조를 하면 전역변수로 사용하는게 좋다던지.,. 뭐 이런 기준들이요.. :cry:

파라메터로 값을 넘겨주는 형태로 구조를 변경해보세요.
그러는 사이 전역변수가 하나둘씩 사라집니다.
그리고 조금 더 소스코드를 보기 좋게 작성 할 수 있는 계기가 됩니다.

쌀밥의 이미지

superkkt wrote:
체크를 해보니 예를들어 a라는 변수는 2~3개 이상의 함수가 참조를 합니다. 이정도면 a라는 변수는 전역변수로 선언해도 좋은가요?

흠.. 어떤 기준이 있다면 이렇게 머리가 안아플텐데요..


정말이지 이런데에 참고할만한 기준이 있다면 좋을텐데...말입니다. ㅎㅎ

이런 문제를 줄이는 방법이..
클래스를 사용하는 방법이 되겠지만
클래스를 사용하더라도 전역으로 사용되어야 하는 객체가 또 있어서..
싱글톤 같은 패턴이 사용되기도 하고요...

제 생각에는...
전역을 완전히 피할수는 없겠지만,
(앞서 적으셨듯이) 사용되는 횟수를 기준으로
전역/로컬을 구분해서는 안될것 같구요.
시야를 기준으로
누구에게 까지 보이게 할것인가 아닌가로 구분해야할것 같습니다.

이런 시야 제한을 할 수 있는 방법이 사실 C에는 거의 없다고 봐야겠지요;;;
extern 하나면 include 할때 다 보이는 셈이 되니까요;;;

꼭 전역이 아니면 절대 절대 안되는 경우만 전역을 사용하는 습관을 기르셔야 할것 같습니다.
짧은 코드의 경우, 전역이 코드를 더 깔끔하게 되어 보이지만
짧은 코드를 작성하는 기간은 짧고,
긴코드로 주름 늘어날 시간은 길테니까요...;ㅎㅎ

일하는 사람들의 희망 민주노동당 : http://www.kdlp.org
반공 교육의 성과로, 민주주의의 반대가 공산주의(또는 사회주의)라고 생각하는 사람이 많다.

anfl의 이미지

필요하고, 현재 구조에서 전역 변수의 사용이 소스를 간결하게 할수 있다면 굳이 전역변수를 없앨 필요는 없다고 생각합니다.
module 별로 파일이 나누어져 있다면 symbol 충돌을 방지하기 위해 static 키워드로 충분할거라고 봅니다.

남의 프로그래밍 철학을 억지로 끼워 맞출려고 하시는게 아니신지 생각됩니다.
전역 변수와 goto 사용의 자제와 같은 남이 만든 룰에 억매이지 마셨으면 하는게 제 생각입니다.
CPU, OS 그리고 사람을 고려해서 자신이 생각하기에 가장 합당하다고 생각 할때는 전역 변수든 goto든 필요하다면 사용하는 것이 자신의 철학 정립하는 길인것 같습니다.

제 프로그래밍 철학을 잠깐 말씀드리겠습니다.
저는 goto에 대해서 할말이 참 많은 사람중에 하나입니다.
대학교 정규 과정을 거친 사람중에 goto를 무조건 쓰면 안된다고 말하는 사람들이 많은것 같습니다.
제가 아는 사람중에 한 사람이 다른 사람이 goto를 쓴걸보고 뭐라고 하더군요.

"goto를 쓰면 안돼는데 왜 썼냐고."

별로 친하지 않고 함부로 대할 수 없는 상황이였기에 말을 하지 않았는데. 그 사람의 요지는 이거였습니다.

"goto를 쓰면 안된다."

스파게티 코드 운운하더군요.
과연 그 사람은 goto가 instruction으로 jmp또는 b로 번역 되는것을 알았는지 궁금하더군요.
if, for, while, switch 모두 내부적으로 goto가 번역되는 jmp, b로 번역되는데 한페이지도 넘어가지 않은 함수에서 goto 하나의 사용에 대해서 운운하는게 우스웠습니다.
switch문의 case가 local label 번역 된다는것을 그 사람은 알고 그런말을 한다고 생각하지 않았습니다.

누군가가 하는 말을 들었을거라는 생각이 들더군요.

결국 그 사람은 자신의 철학이 없는 사람이였고, 그래서 어쩔수 없이 자신이 아는 사람중에 가장 권위 있는 사람의 철학을 모방했을거라고 생각합니다.

정말 자신이 생각하기에 전역 변수를 없애야 한다면 없애세요.
그건 자신의 프로그래밍 철학입니다.
그렇지만 만약에 지금이 더 간단한데 단지 "전역 변수는 없는게 좋은거니깐..." 이라고 생각한다면 (물론 symbol 충돌이 아주 적게 발생하는 상황에서...) 그건 자신의 프로그래밍 철학이 아닙니다.

만약 그렇다면 자신의 프로그래밍 철학을 만드십시요. 전자, TTL, CMOS, CPU, 컴파일러, OS, language, 사람등등 하나씩 정복해 나가면서 자신의 철학을 만드시길 바랍니다.


c0d3h4ck의 이미지

May the F/OSS be with you..

abcdefg의 이미지

HOST , cobol 환경에서 UNIX, Ansi C 로
다운사이징한 소스를 손볼 일이 있었는데

매개변수 가능한 안쓰고 static 전역변수 쓴거말고는
모든게 완벽한 소스였습니다.

며칠을 곰곰히 생각해 보니 다운사이징하면서

C 에 익숙치 못한 비지니스로직 개발자들이
손쉽게 적응할 수있도록 고육지책을 쓴거라 생각되더군요

그 상황에서 억지로 static 전역변수 안쓸려고했으면

보기엔 좋을지 모르지만
상당히 난해한 소스가돼서 두고 두고 골치 썩였을것 같더군요 ...

hyperhidrosis의 이미지

전역변수를 구조체로 묶는 방법도 있습니다..

sturct Global
{
int a;
char* b;
double c;
};

Global global;

void x()
{
global.a = 0;
}

///////////////

이렇게 쓰면 나중에 이 변수가 뭔지 알아볼때 나름대로 편해집니다.

antibug의 이미지

goto를 쓰건 (void *)를 남발하건 자신이 뭘 하고 있는지 잘 알고 있다면
사용하는 것 자체를 문제삼을 수는 없죠. 전역 변수 또한 마찬가지구요.
다만 어떤 코딩 스타일을 가진 다는 것은 의도적으로 노력하지 않으면
쉽지 않은데다가 오래 걸리기까지 하죠. 그러니 가급적 '의도적'으로 좋은
방향으로 가야 할 것 같습니다.

제 경우 C로 작업할 경우에는 거의 전역변수를 사용하지 않습니다.
지금 작업하고 있는 것을 보면... 없군요.

전역 변수를 없애는 가장 간단한 방법은 우선 전역 함수를 사용하는 것입니다.
전역 변수를 직접 엑세스하는 대신 get/set 함수 호출을 사용하는 것이죠.
이로써 읽기 위한 엑세스와 쓰기 위한 엑세스가 구분이 되죠.

다음으로는 특정 모듈에 종속적인 변수들은 파일 안에 static으로 만들어
주면 차후에 이 변수를 외부에서 엑세스하는 것을 막을 수 있죠.

가급적 함수를 만들 때에는 모듈 로컬 변수와 파라미터, 그리고 자동 변수
외에는 사용하지 않도록 하세요. 소스 코드 읽기도 좋아지고, 전역변수
문제도 점차 사라질 겁니다. 어떤 변수를 엑세스해야 한다면 caller가 그
변수값을 넘겨주던 포인터를 넘겨주던 하여간 파라미터로 넘겨주게 디자인
해보세요.

제목에도 밝혔지만 이런 일반적인 얘기가 통하지 않는 경우도 있습니다.
이런 경우에는 마음껏 전역변수를 써도 상관없겠죠. 예를 들어 제 경우엔
16비트 마이컴에서 타이머 쪽에서 전역변수를 사용합니다. 이쪽은 속도가
매우 중요해서 파라미터로 넘겨주고 어쩌고 하다가는 스펙 아웃이라서...

필요한 전역 변수가 매우 많다면 이 변수를 구조체로 묶어서 보내주는 방법도
있구요. 포인터를 넘겨줄 때에는 그것이 read only인지 writable인지 꼭
명시하세요. const를 사용하면 됩니다.

이정도면 웬만한 전역변수는 없어질 것 같네요.

--------------------------------------
재미없는 일은 하지 말자는 인간 쓰레기.
-.-;

creativeidler의 이미지

C에서는 파일 하나를 일종의 클래스로 보는 방식으로 코딩을 할 수 있습니다. 이런 경우에는 파일 내의 전역 변수는 일종의 멤버 변수처럼 취급하고 다른 파일에서는 함수만 가져다 쓰면 됩니다.

Quote:
남의 프로그래밍 철학을 억지로 끼워 맞출려고 하시는게 아니신지 생각됩니다.
전역 변수와 goto 사용의 자제와 같은 남이 만든 룰에 억매이지 마셨으면 하는게 제 생각입니다.
CPU, OS 그리고 사람을 고려해서 자신이 생각하기에 가장 합당하다고 생각 할때는 전역 변수든 goto든 필요하다면 사용하는 것이 자신의 철학 정립하는 길인것 같습니다.

이 말에 동의합니다. 남의 만든 룰은 다시 자신의 기준으로 타당성을 점검해봐서 옳은 것 같으면 받아들이고 아니면 굳이 받아들일 필요 없습니다. 아직 전역 변수의 해악에 대해 잘 모르겠다면 일단 써보는 것도 한 방법입니다. 남이 이론적으로 전역 변수의 해악을 설명하는 것이 와닿지 않는다면 방법은 직접 써봐서 느끼는 것 뿐이죠. 직접 써봤더니 괜찮더라? 그러면 그냥 쓰면 됩니다.

그러나, 사실 전역 변수는 어느 정도 기준이 있죠. 전역 변수가 아니면 도저히 구현할 수 없는 경우, 이런 경우를 제외하면 안 쓰는 게 좋습니다. goto문도 제 생각에는 goto를 안 쓰는 게 더 읽기 쉬운 코드를 만드는 것 같습니다. 아직까지 goto문을 써야 더 보기 좋은 경우는 없었던 듯. 어차피 브랜치나 점프가 된다면 가독성이 좋은 if가 더 효과적이지 않겠습니까. 브랜치 니모닉을 pseudo 코드로 쓸 때는 if로 표기하기도 하죠. 짧은 함수라 해도 goto 문이 필요하다면 10라인은 될 텐데 언어와 상관 없이 평균 10라인 당 하나의 버그가 발생할 가능성이 있다는 연구 결과를 생각해본다면 goto는 다양한 대안이 있는 만큼 안 쓰는 게 좋지 않을까요.

jsunam의 이미지

전역변수 사용에 대한 이야기에서 잠깐 빗나가는 것 같은데,
goto문 사용에 대한 이야기가 나와서 저도 한가지만 언급하겠습니다.

매우 유명한 프로그래머가 있죠? Don Knuth라고...

그 할아버지가 Adventure라는 일종의 머드게임(?)을 작성하시면서, 서두에
한 말이 있습니다. (그 프로그램에는 goto문이 참 많이도 쓰였더군요.)

"By the way, if you don't like goto statements, don't read this.
(And don't read any other programs that simulate multistate systems.)"

goto문을 무조건 쓰지 말아야 하는 것은 아닌가 봅니다.
그래도 피할 수 있다면 goto문 사용을 자제하는 방향으로... :)

댓글 첨부 파일: 
첨부파일 크기
Binary Data 0바이트
다크슈테펜의 이미지

그냥 자바라면 클래스 하나에 다 때려박고 C#이라면 구조체에다가 다 때려 박습니다.깔끔해요....

인생이란게 다 그런게 아니겠어요....? 뭘(?)
http://schutepen.egloos.com

익명 사용자의 이미지

antibug wrote:
전역 변수를 없애는 가장 간단한 방법은 우선 전역 함수를 사용하는 것입니다.
전역 변수를 직접 엑세스하는 대신 get/set 함수 호출을 사용하는 것이죠.
이로써 읽기 위한 엑세스와 쓰기 위한 엑세스가 구분이 되죠.

저도 이 방법을 추천합니다.
함수 호출이 힘들면 매크로 함수로 만들어 써도 되구요..

지금은 그냥 변수 참조일 뿐이지만 언젠가는 스펙이 바뀌어 그 변수를 일괄적으로 가공해야 할지 모릅니다. 이때 get/set 함수가 눈물나게 고마워 질겁니다. :roll:

(사족)
지금 딴 사람이 짠 소스를 관리하고 있는데 전에 짠 사람이 전역변수를 남발하는 바람에 고생하고 있습니다. :evil:

lifthrasiir의 이미지

creativeidler wrote:
C에서는 파일 하나를 일종의 클래스로 보는 방식으로 코딩을 할 수 있습니다. 이런 경우에는 파일 내의 전역 변수는 일종의 멤버 변수처럼 취급하고 다른 파일에서는 함수만 가져다 쓰면 됩니다.

Quote:
남의 프로그래밍 철학을 억지로 끼워 맞출려고 하시는게 아니신지 생각됩니다.
전역 변수와 goto 사용의 자제와 같은 남이 만든 룰에 억매이지 마셨으면 하는게 제 생각입니다.
CPU, OS 그리고 사람을 고려해서 자신이 생각하기에 가장 합당하다고 생각 할때는 전역 변수든 goto든 필요하다면 사용하는 것이 자신의 철학 정립하는 길인것 같습니다.

이 말에 동의합니다. 남의 만든 룰은 다시 자신의 기준으로 타당성을 점검해봐서 옳은 것 같으면 받아들이고 아니면 굳이 받아들일 필요 없습니다. 아직 전역 변수의 해악에 대해 잘 모르겠다면 일단 써보는 것도 한 방법입니다. 남이 이론적으로 전역 변수의 해악을 설명하는 것이 와닿지 않는다면 방법은 직접 써봐서 느끼는 것 뿐이죠. 직접 써봤더니 괜찮더라? 그러면 그냥 쓰면 됩니다.

그러나, 사실 전역 변수는 어느 정도 기준이 있죠. 전역 변수가 아니면 도저히 구현할 수 없는 경우, 이런 경우를 제외하면 안 쓰는 게 좋습니다. goto문도 제 생각에는 goto를 안 쓰는 게 더 읽기 쉬운 코드를 만드는 것 같습니다. 아직까지 goto문을 써야 더 보기 좋은 경우는 없었던 듯. 어차피 브랜치나 점프가 된다면 가독성이 좋은 if가 더 효과적이지 않겠습니까. 브랜치 니모닉을 pseudo 코드로 쓸 때는 if로 표기하기도 하죠. 짧은 함수라 해도 goto 문이 필요하다면 10라인은 될 텐데 언어와 상관 없이 평균 10라인 당 하나의 버그가 발생할 가능성이 있다는 연구 결과를 생각해본다면 goto는 다양한 대안이 있는 만큼 안 쓰는 게 좋지 않을까요.

전역 변수 얘기하다가 갑자기 goto로 넘어 가서 좀 거시기하지만;;; C에서 goto는 일종의 필요악에 가깝지 않나 싶습니다. 물론 Edsger Dijkstra가 지적했듯이 goto 문은 구조화되어 있지 않기 때문에 코드를 어렵게 만들 가능성이 높지만, 그럼에도 불구하고 예외 처리 흉내라던지 다중 루프를 탈출한다던지 switch 문에서의 응용이라던지 쓸 데가 여전히 남아 있다는 게 문제죠. (물론 다양한 대안이 있긴 합니다만, 각각 장단이 있으니까...) 자기가 무슨 일을 하고 있는 지 제대로 인식하기만 한다면 goto 문이 배척될 이유는 없다고 생각합니다. 물론 "제대로" 말이죠. :p

덤으로, 저는 지금까지 C 프로그래밍을 하면서 전역 변수는 심심찮게(-_-) 써 봤고 goto 문은 몇 번인가 써 본 것 같습니다. 전역 변수는 주로 "절대로 다른 곳에서 안 쓸 것이고 200줄 내외의 짧은 코드"에서 많이 등장하더군요. 요즘은 이런 용도로는 파이썬을 씁니다 :)

- 토끼군

IsExist의 이미지

goto는 예외적인 상황에서만 사용하는게 좋습니다.
로우레벨 언어에 익숙한 구문이고 함수의 길이를 길게 만들수
있는 경향이 높습니다. 압축적으로 표현하기보다는 길게 표현할려는
경향이 짙어집니다.

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

uriel의 이미지

creativeidler wrote:

아직까지 goto문을 써야 더 보기 좋은 경우는 없었던 듯. 어차피 브랜치나 점프가 된다면 가독성이 좋은 if가 더 효과적이지 않겠습니까. 브랜치 니모닉을 pseudo 코드로 쓸 때는 if로 표기하기도 하죠. 짧은 함수라 해도 goto 문이 필요하다면 10라인은 될 텐데 언어와 상관 없이 평균 10라인 당 하나의 버그가 발생할 가능성이 있다는 연구 결과를 생각해본다면 goto는 다양한 대안이 있는 만큼 안 쓰는 게 좋지 않을까요.

개인적으로 딱 한 가지 경우에만 goto를 사용합니다. 하나의 함수 안에서 조건에 따라서 여러 가지 에러 처리 루틴이 있고 에러에 따라서 리턴 하기 전에 여러 가지 일을 하는 경우 goto를 사용하는 게 훨씬 더 깔끔하더군요. exception으로 구현하기는 좀 무겁고 그렇지 않으면 nested if가 많아져서 코드가 지저분해집니다. 이럴 때에 ON_ERROR 같은 부분을 정해 놓고 해당 부분에

error_code = 2;
goto ON_ERROR;
.
.
.
ON_ERROR:
// common clean-up like memory deallocation
return error_code

같은 식으로 처리해 버리는게 더 쉽더군요.
chadr의 이미지

uriel wrote:
creativeidler wrote:

아직까지 goto문을 써야 더 보기 좋은 경우는 없었던 듯. 어차피 브랜치나 점프가 된다면 가독성이 좋은 if가 더 효과적이지 않겠습니까. 브랜치 니모닉을 pseudo 코드로 쓸 때는 if로 표기하기도 하죠. 짧은 함수라 해도 goto 문이 필요하다면 10라인은 될 텐데 언어와 상관 없이 평균 10라인 당 하나의 버그가 발생할 가능성이 있다는 연구 결과를 생각해본다면 goto는 다양한 대안이 있는 만큼 안 쓰는 게 좋지 않을까요.

개인적으로 딱 한 가지 경우에만 goto를 사용합니다. 하나의 함수 안에서 조건에 따라서 여러 가지 에러 처리 루틴이 있고 에러에 따라서 리턴 하기 전에 여러 가지 일을 하는 경우 goto를 사용하는 게 훨씬 더 깔끔하더군요. exception으로 구현하기는 좀 무겁고 그렇지 않으면 nested if가 많아져서 코드가 지저분해집니다. 이럴 때에 ON_ERROR 같은 부분을 정해 놓고 해당 부분에

error code = 2;
goto ON_ERROR;

같은 식으로 처리해 버리는게 더 쉽더군요.

저도 goto문은 그런식으로 처리하는데 사용합니다. 오히려 저런 경우에 goto문을 안쓸려고 하면 더욱더 스파게티 코드가 되어가더군요..

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

lovewar의 이미지

superkkt wrote:

어떤 기준이 있다면 이렇게 머리가 안아플텐데요.. 예를들어 몇개 이상의 함수가 참조를 하면 전역변수로 사용하는게 좋다던지.,. 뭐 이런 기준들이요.. :cry:

이 부분은 의미가 강하다고 생각합니다.

프로그램을 자세히 보면 두가지 부분으로 나누어집니다.
자료(data) 기능과 함수(function) 기능으로 분리됩니다
[기능점수(Function Point) 산출법].
자료 영역에서는 임시자료와 영구자료로 구분되는데
여기서 영구성 자료가 되는것들을 최종적으로 전역에 놓고
구현하는 것이 좋겠습니다(설계문서와도 밀접한 관계가 있습니다).

나머지 부분은 경험에 경험을 통해서 도출되는 부분들도 있을것 같습니다(속도를 위해서 메모리를 불가결하게 사용한다든지.. ).

superkkt의 이미지

Anonymous wrote:
antibug wrote:
전역 변수를 없애는 가장 간단한 방법은 우선 전역 함수를 사용하는 것입니다.
전역 변수를 직접 엑세스하는 대신 get/set 함수 호출을 사용하는 것이죠.
이로써 읽기 위한 엑세스와 쓰기 위한 엑세스가 구분이 되죠.

저도 이 방법을 추천합니다.
함수 호출이 힘들면 매크로 함수로 만들어 써도 되구요..

지금은 그냥 변수 참조일 뿐이지만 언젠가는 스펙이 바뀌어 그 변수를 일괄적으로 가공해야 할지 모릅니다. 이때 get/set 함수가 눈물나게 고마워 질겁니다. :roll:

(사족)
지금 딴 사람이 짠 소스를 관리하고 있는데 전에 짠 사람이 전역변수를 남발하는 바람에 고생하고 있습니다. :evil:

전역함수라는게 어떤걸 얘기하는지 잘 이해가 안됩니다.. :oops: 간단한 소스코드 좀 부탁드려도 될까요?

======================
BLOG : http://superkkt.com

uriel의 이미지

그런데, 전역 변수에 어울리는 변수가 있긴 하나요? 물론 제가 C++로 코딩을 하기 때문에 class의 멤버 변수를 주로 사용하긴 하지만 "전역 상수"는 사용해도 전역 변수는 거의 사용한 기억이 없네요.

딱 하나 전역 변수로 쓰는 경우는 쓰레드를 만들 때에 크리티컬 섹션/뮤텍스를 사용하면 코드가 좀 길어지는 경우에 전역 변수로 -이 경우는 사용하는 쓰레드에서 앞부분에 초기화를 해서 종료하기 전에 풀어 주었습니다- 넘겨 준 경우는 있긴 합니다. STL vector였던가... list였던가인데 로컬 변수일 경우 쓰레드에서 메모리 누수가 나더군요. UI쪽 쓰레드라 별 걱정 없이 전역 변수로 사용하긴 했습니다.

제가 최적화 쪽은 별로 소질이 없어서 이 경우 전역 변수를 많이 써 본 경험은 없네요. 아마 조건문을 인덱스로 호출하는 함수로 만들어 넣고 그 함수 포인터 배열을 사용한다면 전역 변수에 넣고 사용해야 할 것 같긴 하군요.

hajunsa의 이미지

Quote:

제가 아는 사람중에 한 사람이 다른 사람이 goto를 쓴걸보고 뭐라고 하더군요.

"goto를 쓰면 안돼는데 왜 썼냐고."

별로 친하지 않고 함부로 대할 수 없는 상황이였기에 말을 하지 않았는데. 그 사람의 요지는 이거였습니다.

"goto를 쓰면 안된다."

저도 첨에 책에서 본것과 강사들의 강의로 goto문을 쓰면 안된다라는 세뇌를

당했더랬죠. 실무를 하다보니 아니왜 goto를 쓰면 안되 써보자. 써보니 이때는

코딩 개념이 잡혀서 일까요? goto문을 쓰면 오히려 깔끔하게 처리 되더군요.

그 이후 이런류의 글을 보면 "아나 왜?"라는 의문 부터 해봅니다.

Quote:

문도 제 생각에는 goto를 안 쓰는 게 더 읽기 쉬운 코드를 만드는 것 같습니다.

저의 경우 오히려 반대군요. goto문을 사용했을때 더 읽기 쉬운 코드가 됬습니다.

lovewar의 이미지

superkkt wrote:

전역함수라는게 어떤걸 얘기하는지 잘 이해가 안됩니다.. :oops: 간단한 소스코드 좀 부탁드려도 될까요?

internal linkage(static) 와 external linkage(extern) 속성을 이용하시면 됩니다.

쌀밥의 이미지

//a.h
extern int a;

// a.cpp
int a;

이런 전역 코드를
//a.h
int GetA();
void SetA(int);

// a.cpp
int a;
int GetA() { return a; }
void SetA(int val) { a = val; }

이런식의 전역 함수로 바꿀 수 있습니다.

이렇게 하면 변수와의 종속성을 좀 더 느슨하게 만들어주지요...

*PS : 저도 Knuth 박사의 'goto 문의 유용성' 논문은 들은적이 있습니다만, 그거 작성 년도가 무지무지 옛날일껍니다.... 아마도 goto 문의 유용성에 대해 논의 하던 시기에 나온 논문일듯...

*PS: 경우에 따라 전역을 피하지 못하는 경우는 발생합니다. 어쩔수 없이 말이죠.
하지만, 좋은 설계는 전역 변수를 줄이는 것입니다. 커플링과 코헤젼 개념으로 전역 변수의 나쁜점을 설명하는 책들이 많이 있으니 참고하세요.

일하는 사람들의 희망 민주노동당 : http://www.kdlp.org
반공 교육의 성과로, 민주주의의 반대가 공산주의(또는 사회주의)라고 생각하는 사람이 많다.

익명 사용자의 이미지

Quote:

*PS: 경우에 따라 전역을 피하지 못하는 경우는 발생합니다. 어쩔수 없이 말이죠.
하지만, 좋은 설계는 전역 변수를 줄이는 것입니다. 커플링과 코헤젼 개념으로 전역 변수의 나쁜점을 설명하는 책들이 많이 있으니 참고하세요.

이 말은 "좋은 설계는 각 모듈간의 종속성을 줄이는 것과 변수 종속성을 줄이는 것이다."라고 바꾸어야 맞다고 생각합니다.

전역 변수를 줄이는것이 좋은 설계가 된다는 보장은 없습니다. 성능이 중요시 되는 모듈에서는 전역함수의 사용보다는 전역 변수의 사용이 맞을 수 있습니다.
모든 프로그램에서 전역 함수가 터부시 되는것은 맞지 않습니다. 변수 종속성이 많이 일어나지 않게 적절히 잘 사용한다면 문제될껀 없습니다.

Quote:

저도 Knuth 박사의 'goto 문의 유용성' 논문은 들은적이 있습니다만, 그거 작성 년도가 무지무지 옛날일껍니다.... 아마도 goto 문의 유용성에 대해 논의 하던 시기에 나온 논문일듯...

또한 goto 역시 마찮가지 입니다. goto를 쓰면 유용한 프로그램이 있고, 유용한 상황이 있습니다. network protocol stack을 짜보시면 goto가 얼마나 유용한지 아실껍니다.
또한 synchronization primitive를 직접 구현하거나, 예외처리를 위해 goto를 쓰면 가독성 및 성능에 좋을만한 상황이 많이 발생합니다. 한 페이지를 넘어가지 않은 한도에서 적절한 goto의 사용 역시 문제될껀 하나도 없습니다.

뭐... 이런 문제로 왈가왈부 할 생각은 없습니다. 각자 철학이 있는데 제 철학을 강요할 생각은 없습니다. 단지 철학이 없는 사람이 책에서 나온 남의 이야기를 맹신하는 것에 경계할뿐입니다.

superkkt의 이미지

쌀밥 wrote:
//a.h
extern int a;

// a.cpp
int a;

이런 전역 코드를
//a.h
int GetA();
void SetA(int);

// a.cpp
int a;
int GetA() { return a; }
void SetA(int val) { a = val; }

이런식의 전역 함수로 바꿀 수 있습니다.

이렇게 하면 변수와의 종속성을 좀 더 느슨하게 만들어주지요...

흠... 이해가 안돼요...... :oops: 저 방법이 어떻게 전역변수를 대신할 수 있는지 모르겠습니다... :(

======================
BLOG : http://superkkt.com

lovewar의 이미지

superkkt wrote:
쌀밥 wrote:
//a.h
extern int a;

// a.cpp
int a;

이런 전역 코드를
//a.h
int GetA();
void SetA(int);

// a.cpp
int a;
int GetA() { return a; }
void SetA(int val) { a = val; }

이런식의 전역 함수로 바꿀 수 있습니다.

이렇게 하면 변수와의 종속성을 좀 더 느슨하게 만들어주지요...

흠... 이해가 안돼요...... :oops: 저 방법이 어떻게 전역변수를 대신할 수 있는지 모르겠습니다... :(

다음과 같이 사용하시면 됩니다.

//Task.h
extern int GetStatus(void);
extern void SetStatus(int);
extern void Task(void);

// Task.c
static int status = 0;   /* 내부(번역단위)에서만 사용한다는 표시 */
extern int GetStatus(void) { return status; }
extern void SetStatus(int stat) { status = stat; }
extern void Task(void) {
  // 생략
  InnerTask();  
  //생략
}
static  void InnerTask(void) { /* 내부(번역단위)에서만 사용한다는 표시 */ 
    // 생략
}

creativeidler의 이미지

글쎄요. goto가 더 깔끔한 코드를 만든다? 그런 경우는 전혀 없다고 해도 과언이 아닐 겁니다. 다음과 같은 코드는..

error_code = 2;
goto ON_ERROR;
.
.
.
ON_ERROR:
// common clean-up like memory deallocation
return error_code

이렇게 바꿀 수 있죠.

  return handleError(2);
  .
  .
}

int handleError(int error_code) {
  // handle error
}

이 쪽이 좀더 명확하지 않습니까? 모든 goto는 function call이나 if로 대체할 수 있습니다. 그리고 그 경우가 좀더 중복 코드를 효과적으로 제거할 수 있죠.

후자 대신 전자를 택해야 하는 경우는 딱 한 가지 경우입니다. function call의 overhead조차 부담스러운 경우죠. 이런 경우가 전혀 없는 건 아니지만 요즘은 웬만한 hard real time에서도 function call을 줄여야 하는 경우는 잘 없죠. 정 문제되면 inline이나 매크로를 쓸 수도 있구요.
[/code]

uriel의 이미지

creativeidler wrote:
글쎄요. goto가 더 깔끔한 코드를 만든다? 그런 경우는 전혀 없다고 해도 과언이 아닐 겁니다. 다음과 같은 코드는..
error_code = 2;
goto ON_ERROR;
.
.
.
ON_ERROR:
// common clean-up like memory deallocation
return error_code

이렇게 바꿀 수 있죠.

  return handleError(2);
  .
  .
}

int handleError(int error_code) {
  // handle error
}

이 쪽이 좀더 명확하지 않습니까? 모든 goto는 function call이나 if로 대체할 수 있습니다. 그리고 그 경우가 좀더 중복 코드를 효과적으로 제거할 수 있죠.

후자 대신 전자를 택해야 하는 경우는 딱 한 가지 경우입니다. function call의 overhead조차 부담스러운 경우죠. 이런 경우가 전혀 없는 건 아니지만 요즘은 웬만한 hard real time에서도 function call을 줄여야 하는 경우는 잘 없죠. 정 문제되면 inline이나 매크로를 쓸 수도 있구요.
[/code]

말씀하신 경우는 그게 더 깔끔합니다만 주석으로 달아 놓은 // common clean-up like memory deallocation 부분 때문에 그게 항상 적용되지는 않습니다. 예를 들어 문제가 된 경우에 메모리 해제를 하고 사용자 메세지를 뿌려주고 리턴을 한다고 생각 해 보면 저런 식으로 외부 함수에게 메모리 해제를 맞기긴 좀 그렇죠. 뭐, 메모리 해제에 사용자에게 메세지를 뿌려주면서 리턴하는 별도의 함수를 만들어서 말씀하신 것처럼 부르는 것도 가능하긴 합니다만, 특별히 더 깔끔하지는 않다고 생각 합니다. HandleErrorAndFreeMemForFunction1() 이런 함수를 만들고 싶지는 않네요. 특정 함수에 아주 커플링된 별도의 함수 하나를 더 만드는 것을 별로 안좋아 하는 사람은 goto를 쓰죠.

creativeidler의 이미지

Quote:
말씀하신 경우는 그게 더 깔끔합니다만 주석으로 달아 놓은 // common clean-up like memory deallocation 부분 때문에 그게 항상 적용되지는 않습니다. 예를 들어 문제가 된 경우에 메모리 해제를 하고 사용자 메세지를 뿌려주고 리턴을 한다고 생각 해 보면 저런 식으로 외부 함수에게 메모리 해제를 맞기긴 좀 그렇죠. 뭐, 메모리 해제에 사용자에게 메세지를 뿌려주면서 리턴하는 별도의 함수를 만들어서 말씀하신 것처럼 부르는 것도 가능하긴 합니다만, 특별히 더 깔끔하지는 않다고 생각 합니다. HandleErrorAndFreeMemForFunction1() 이런 함수를 만들고 싶지는 않네요. 특정 함수에 아주 커플링된 별도의 함수 하나를 더 만드는 것을 별로 안좋아 하는 사람은 goto를 쓰죠.

글쎄요. 실제 코드를 보여주시면 역시 비교가 좀더 명확하게 되리라 생각합니다만 그냥 이론상으로 이야기한다면, goto를 extract method하는 건 오히려 orthogonality를 높여 주기 때문에 coupling이 줄어듭니다. 만약에 두 함수가 똑같은 free를 해야 하는 상황이면 함수 내의 goto로 해결할 수 없기 때문에 두 함수에 똑같은 코드가 들어가죠. 반면 함수로 처리하면 두 함수에서 그냥 호출하면 되니까 coupling이 줄어듭니다. goto보다 function call이 유리한 점이 바로 이런 거 아니겠습니까. 그리고 error 처리를 하고 돌아와서 함수 종료 전에 free를 해도 되는 거구요.

덧붙여, 요즘은 OOP에 익숙한 사람들이 C로 회귀하는-_- 일이 많아지면서 C에서도 OOP적인 개념으로 코딩하는 경우가 많아지고 있습니다. struct와 function pointer를 사용하는 방식을 말하는 게 아니라 C에서 file이 하나의 scope라는 점을 이용해서 file을 class로 간주하고 file scope의 전역 변수를 클래스 멤버 변수, file scope의 함수를 private method, 전역 함수를 public method로 간주하죠. 이런 경우 destructor 개념의 함수를 하나 둬서 여기서 일괄적으로 free 작업을 해주기도 합니다. 물론 다형성 같은 건 function pointer의 도움 없이는 어렵지만요. 사실 이런 스타일은 별반 새로운 게 아니라 C에서 원래 많이 쓰이던 스타일이고 리눅스 커널의 코드에서도 왕왕 보이는 스타일인데 OOP 개념의 흡수로 좀더 체계화되어 가고 있죠.

superkkt의 이미지

lovewar wrote:
superkkt wrote:
쌀밥 wrote:
//a.h
extern int a;

// a.cpp
int a;

이런 전역 코드를
//a.h
int GetA();
void SetA(int);

// a.cpp
int a;
int GetA() { return a; }
void SetA(int val) { a = val; }

이런식의 전역 함수로 바꿀 수 있습니다.

이렇게 하면 변수와의 종속성을 좀 더 느슨하게 만들어주지요...

흠... 이해가 안돼요...... :oops: 저 방법이 어떻게 전역변수를 대신할 수 있는지 모르겠습니다... :(

다음과 같이 사용하시면 됩니다.

//Task.h
extern int GetStatus(void);
extern void SetStatus(int);
extern void Task(void);

// Task.c
static int status = 0;   /* 내부(번역단위)에서만 사용한다는 표시 */
extern int GetStatus(void) { return status; }
extern void SetStatus(int stat) { status = stat; }
extern void Task(void) {
  // 생략
  InnerTask();  
  //생략
}
static  void InnerTask(void) { /* 내부(번역단위)에서만 사용한다는 표시 */ 
    // 생략
}

그럼 전역함수가 변수의 숫자만큼 생겨야 하는건가요? 그렇다면 하나의 전역함수에서 모든 변수를 처리하는 방법은 없을까요?
그리고 저런 방법으로 변수를 다룰때는 status++ 같은 코드는 SetStatus(GetStatus() + 1) 이렇게 사용해야 하는거죠?

======================
BLOG : http://superkkt.com

doldori의 이미지

superkkt wrote:
흠... 이해가 안돼요...... :oops: 저 방법이 어떻게 전역변수를 대신할 수 있는지 모르겠습니다... :(

정확히 말하면 전역변수를 대신한다기보다 그 변수에 접근하는 방법을 통제하는 것이죠.
다른 모듈에서 그 변수에 직접 사용하게 하는 대신 필요한 동작 또는 연산을 함수 형태로
제공하는 것입니다. 이렇게 하여 모듈간의 종속성이 느슨해지고 더 유연한 구조가
됩니다. 예를 들어
 // one.h
struct TheOne { };
extern struct TheOne neo;

// useNeo.c
#include "one.h"

// twiddling with neo at users' own risk

이렇게 하기보다
// one.h
struct TheOne;

struct TheOne* whoIsThere(void);
void playSuperman(struct TheOne*);

// one.c
#include "one.h"
struct TheOne { };

struct TheOne neo;

struct TheOne* whoIsThere(void) { return &neo; }

이런 식이죠. 이 모듈의 사용자는 neo의 존재에 대해서는 알 수도, 알 필요도 없고
단지 모듈에서 제공하는 함수로 원하는 작업을 할 수 있는 것입니다. 그러면 실수를
줄일 수 있고, 이 모듈의 작성자는 외부에 알려지는 함수만 그대로 두고 내부적인
구현은 필요에 따라 변경할 수 있게 됩니다. 이것이 데이터 은닉과 추상화의 장점입니다.

superkkt wrote:
그럼 전역함수가 변수의 숫자만큼 생겨야 하는건가요? 그렇다면 하나의 전역함수에서 모든 변수를 처리하는 방법은 없을까요?

get/set 으로 설명하면 '함수 개수 == 변수 개수'라고 오해를 할 수 있는데,
이 경우 변수 이름에서 함수 이름으로 바뀌었을 뿐 본질적으로 달라진 것은 없습니다.
중요한 것은 사용자가 변수에 접근한다는 것은 뭔가 원하는 작업을 하기 위한 과정인데,
모듈의 작성자는 변수 대신 그 작업을 할 수 있는 기능을 제공하는 것이라고
이해하시면 되겠습니다.

이제 하나의 전역 함수에서 (서로 연관성이 없는) 모든 변수를 처리하도록 하는 것이
별로 좋은 방법이 아니라는 것도 이해하셨으리라 믿습니다.

익명 사용자의 이미지

superkkt wrote:

그럼 전역함수가 변수의 숫자만큼 생겨야 하는건가요? 그렇다면 하나의 전역함수에서 모든 변수를 처리하는 방법은 없을까요?

이것은 설계에 따라 구현이 달라집니다. 고민해 보시고 그런 구현을
가능하게끔 할 수 있는 방법이 있을겁니다(연관성이 있다는 가정하여).

전역함수를 숫자만큼 만들고 싶지 않다면, 명명 규칙을 잘 만들면 도움이 됩니다.

함수로 구현하나 명명규칙으로 구현하나 비슷할 것입니다. 다만 함수로 하게되면 접근자체를 함수를 통해서 하기때문에 개발자의 오류(바쁘거나, 또는 혼동)를 좀더 줄일수는 있을겁니다.

superkkt wrote:

그리고 저런 방법으로 변수를 다룰때는 status++ 같은 코드는 SetStatus(GetStatus() + 1) 이렇게 사용해야 하는거죠?

이런 방법도 있습니다.


extern void AddStatus(int inc) {
     status += inc;
}

또는

extern int AddStatus(int inc) {
     status += inc;

     return status;
}

환경에 따라서 다르게 설계되며 모듈로 하고자한다면 많이 사용하는 것을 선택하시면 됩니다.

죠커의 이미지

anfl wrote:
스파게티 코드 운운하더군요.
과연 그 사람은 goto가 instruction으로 jmp또는 b로 번역 되는것을 알았는지 궁금하더군요.
if, for, while, switch 모두 내부적으로 goto가 번역되는 jmp, b로 번역되는데 한페이지도 넘어가지 않은 함수에서 goto 하나의 사용에 대해서 운운하는게 우스웠습니다.
switch문의 case가 local label 번역 된다는것을 그 사람은 알고 그런말을 한다고 생각하지 않았습니다.

내부적으로 구현이 어떻게 되느냐와 스파게티 코드가 될 수 있는 가능성 간에는 상관관계가 없습니다. 이 이야기는 에져 다익스트라의 이야기를 하면서 보충하겠습니다.

쌀밥 wrote:
*PS : 저도 Knuth 박사의 'goto 문의 유용성' 논문은 들은적이 있습니다만, 그거 작성 년도가 무지무지 옛날일껍니다.... 아마도 goto 문의 유용성에 대해 논의 하던 시기에 나온 논문일듯...

크누스 교수의 논문이 오래된 것이라면 에져 다익스트라의 "Goto statements considered harmful"은 더 오래된 글입니다. 오래되었다고 해서 배척할 이유는 없습니다. 오히려 더 소중한 글들입니다.

에져 다익스트라가 주장했던 것은 프로그래머가 흐름을 쫓아갈 수 없기 때문에 (texual index를 잃어버린다고 표현합니다.) GOTO가 문제가 된다는 것이었습니다.

1: i := 4
2: i := i + 1
3: goto 3

위의 코드가 있다면 이 코드에서 현재 실행 시점이 2번이라고 할때 1번 수행 다음인지 3번 수행 다음인지 알 수 없고 이것이 프로그래밍을 어렵게 만드는 요인이라고 보았던 것입니다. 그리고 현재 실행지점이 2번일때 1번 후인지 3번 후인지 설명하실 수 있는 분이 없다면 이 코드를 스파게티 코드로 불러도 무방할 것입니다.

이 문제를 해결하기 위해서는 필연적으로 고수준의 syntax sugar가 필요하다는 것이 밝혀졌고 반복과 분기 등을 이용하는 프로그래밍 기법이 발전해나갔습니다. 이것이 구조적 프로그램의 시작입니다.

여기서 주목할 부분은 두가지가 있습니다. 첫째는 에져 다익스트라가 비판한 이유가 textual index를 잃어버리기 때문에 비판했다는 것입니다. 위에서 많은 분들이 이야기 하셨던 예외 처리와 같이 사실상 순수한 프로그램의 로직과 별도로 고려해야 하는 부분은 goto를 배격할 이유가 없다는 것입니다. 그래서 다익스트라도 편집자가 자신의 논문에 "Goto statements considered harmful"이란 이름을 붙인 것에 대해서 매우 아쉬워했습니다.

두번째는 기존의 반복과 분기문으로 개념적으로 깨끗한 해결이 못될 경우에는 저 논리를 따를 필요가 없다는 것입니다. 예외의 경우에 고전적인 구조적 프로그래밍에서 깔끔하게 다룰 방법이 없습니다.

따라서 우리가 첫번째와 두번째에 어긋나는 사안에 대해서 goto를 적용하는 것은 에져 다익스트라도 환영할 것입니다. 반면에 우리가 쓸모없는 goto를 사용하는 것은 수십년 전에 선인들의 논쟁에서 어떠한 교훈도 얻지 못한 것입니다.

마지막으로 에져 다익스트라가 쓴
Goto staments considered harrmful(http://www.acm.org/classics/oct95/)을 소개합니다.

정태영의 이미지

creativeidler wrote:
글쎄요. goto가 더 깔끔한 코드를 만든다? 그런 경우는 전혀 없다고 해도 과언이 아닐 겁니다.

아래 같은 경우 상당히 유용합니다...

중간에 어떤 과정이든지 에러가 날 경우 goto error;
.
.
.
error:
  jpeg_destroy_decompress (&cinfo);
  if (row)
    gdFree (row);
  if (im)
    gdImageDestroy (im);
  return 0;
}

이렇게 에러가 일어났을 경우 동일하게 해야할 동작이 있다면 goto 도 좋다고 봅니다... 뭐 물론 error란 함수를 정의하고 return error(); 하는 방법도 있지만...

좀 더 다단계 에러처리가 필요할 경우엔 더욱 유용하구요...

error 상황에서 첫번째 메모리만 해제하면 되는경우 goto err1; 두번째메모리까지 해제하면 되는경우 goto err2;

err2:
free(mem2);
mem2 = NULL;

err1:
free(mem1);
mem1 = NULL;

뭐 대강 요ㅤㄹㅗㅎ게 =3=33

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

cronex의 이미지

goto 문이 매무 유용했던 적이라면.....
for랑 if가 겹쳐서 블럭이 약 10개정도까지 들어간적이 있었는데...
몇몇 경우에는 조건을 비교하고는 만족하면
바로 가장 바깥 for문으로 나가야 했죠 =_=
for문만 4개... if문으로 매번 비교해가면서 나가는건 거의 불가능...

결국 goto로 한번에 해결됐었습니다.

for ( ) {
    for ( ) {
        for ( ) {
            for ( ) {
                ...
                if ( test( ) ) goto RESTART
                ...
            }
        }
    }
    RESTART :
}

이런 경우였다고나 할까요 =_=;;
여기서 break를 써서 돌아오려면
저 test 함수의 return을 저장해둘 변수가 필요하고
for문 블록 뒤에 매번 if문을 둬서 break 시켜야하고....
더 복잡해지죠 보기도 더 어렵고요.
(실제로는 for문 앞에 if문도 붙고 해서 더 깊이 들어가 있었죠..
지금은 for문만 표시한거구요.)

------------------------------------------------------------
이 멍청이~! 나한테 이길 수 있다고 생각했었냐~?
광란의 귀공자 데코스 와이즈멜 님이라구~!

익명 사용자의 이미지

정태영님의 코드 역시 extract method를 통해 function call로 대체하는 것이 좋다고 생각됩니다. 사실 function call이라는 게 컴파일되면 결국 파라미터 셋하고 점프하는 거기 때문에 goto나 다를 바가 없습니다. 반대로, goto는 모두 function call로 바꿀 수 있다는 얘기죠. 그런데 function call이 goto보다 좀더 읽기 쉽고 직관적이기 때문에 goto를 쓰지 말라고 하는 것이죠.

cronex님의 코드, 중복 for 문 빠져나가기는 오랫동안 goto 문의 생존 이유로 여겨져왔습니다만 두 가지 대안이 있습니다. 첫째는 test()를 저장하는 변수를 하나 더 두고 for 문의 조건절에서 이를 검사하는 방법입니다. 이 방법이 코드는 좀더 늘어납니다만 for문이 언제까지 수행되는가에 대해 조건절에 아예 명시가 되기 때문에 goto를 따라가보지 않아도 루프가 언제까지 도는 건지 알기가 쉽습니다. 말하자면 좀더 self-descriptive code가 되는 셈이죠.

또다른 방법은 역시 function call인데 내부 루프를 function call로 만들고 extract된 함수 안에서 조건문을 평가해서 return을 해버리는 겁니다. 함수 중간에 리턴하는 것이 예전에는 나쁜 습관이라고 햇지만 요즘은 다시 오히려 좋은 습관이라는 평가가 나오기 있기 때문에 이렇게 해결하기도 하죠.

한 가지 더 이야기한다면, 블럭이 10개씩 들어가 있다면 그건 그 자체로 이해하기 아주 어려운 코드입니다. 굳이 goto가 아니더라도 말이죠. indent를 4로 잡아도 40칸을 순전히 블럭만을 위해 할당하는 셈이 되는데 알고리즘도 없는 단순 html 코드도 indent가 6~7개씩 들어가면 헤매기 시작하는데 복잡한 알고리즘이 담긴 코드라면 goto 문제가 아니더라도 extract method를 해주는 것이 좋지 않을까 싶습니다.

죠커의 이미지

creativeidler. wrote:
정태영님의 코드 역시 extract method를 통해 function call로 대체하는 것이 좋다고 생각됩니다. 사실 function call이라는 게 컴파일되면 결국 파라미터 셋하고 점프하는 거기 때문에 goto나 다를 바가 없습니다. 반대로, goto는 모두 function call로 바꿀 수 있다는 얘기죠. 그런데 function call이 goto보다 좀더 읽기 쉽고 직관적이기 때문에 goto를 쓰지 말라고 하는 것이죠.

cronex님의 코드, 중복 for 문 빠져나가기는 오랫동안 goto 문의 생존 이유로 여겨져왔습니다만 두 가지 대안이 있습니다. 첫째는 test()를 저장하는 변수를 하나 더 두고 for 문의 조건절에서 이를 검사하는 방법입니다. 이 방법이 코드는 좀더 늘어납니다만 for문이 언제까지 수행되는가에 대해 조건절에 아예 명시가 되기 때문에 goto를 따라가보지 않아도 루프가 언제까지 도는 건지 알기가 쉽습니다. 말하자면 좀더 self-descriptive code가 되는 셈이죠.

또다른 방법은 역시 function call인데 내부 루프를 function call로 만들고 extract된 함수 안에서 조건문을 평가해서 return을 해버리는 겁니다. 함수 중간에 리턴하는 것이 예전에는 나쁜 습관이라고 햇지만 요즘은 다시 오히려 좋은 습관이라는 평가가 나오기 있기 때문에 이렇게 해결하기도 하죠.

한 가지 더 이야기한다면, 블럭이 10개씩 들어가 있다면 그건 그 자체로 이해하기 아주 어려운 코드입니다. 굳이 goto가 아니더라도 말이죠. indent를 4로 잡아도 40칸을 순전히 블럭만을 위해 할당하는 셈이 되는데 알고리즘도 없는 단순 html 코드도 indent가 6~7개씩 들어가면 헤매기 시작하는데 복잡한 알고리즘이 담긴 코드라면 goto 문제가 아니더라도 extract method를 해주는 것이 좋지 않을까 싶습니다.

에져 다익스트라는 반복문조차도 필요없는 요소라고 보았습니다. 하지만 현실적인 이유로 (스택의 과도한 사용이나 속도 등의 이유로) 반복문을 사용하는 것을 추천했습니다.

오프 토픽이지만 분기, extract method 만으로 재귀구문이 일상화 되는 날이 올까요? 컴퓨터의 성능은 올라가지만 그만큼 요구되는 성능도 같이 올라가는게 아쉽습니다.

익명 사용자의 이미지

CN

Quote:
에져 다익스트라는 반복문조차도 필요없는 요소라고 보았습니다. 하지만 현실적인 이유로 (스택의 과도한 사용이나 속도 등의 이유로) 반복문을 사용하는 것을 추천했습니다.

당신이 한 말중에서 당신의 말은 어디있는거요?

moonzoo의 이미지

전역변수를 쓰는 기준중 하나는

전역변수가 있다는 사실을 몰라도 무방할 때 라고 봅니다.

간단한 예로 turnLeft() , turnRight() 함수를 통해서

Direction변수를 컨트롤 하는 겁니다. 개발자는 Direction이라는

변수가 있는지 알필요도 없고 변수자체를 추적할 필요도 없습니다.

만약 전역변수의 값을 개발자가 추적하고 이를 조건문등에서

평가해야할 필요가 있다면,

전역변수의 값이 어디서 어떻게 바뀌는지 꿰뚫고 있는다는 것은

그야말로 오쒯~ 입니다 --a

====================

goto에 관한 것은 예외처리시 매우 쓸만하는 것~

죠커의 이미지

moonzoo wrote:
전역변수를 쓰는 기준중 하나는

전역변수가 있다는 사실을 몰라도 무방할 때 라고 봅니다.

간단한 예로 turnLeft() , turnRight() 함수를 통해서

Direction변수를 컨트롤 하는 겁니다. 개발자는 Direction이라는

변수가 있는지 알필요도 없고 변수자체를 추적할 필요도 없습니다.

만약 전역변수의 값을 개발자가 추적하고 이를 조건문등에서

평가해야할 필요가 있다면,

전역변수의 값이 어디서 어떻게 바뀌는지 꿰뚫고 있는다는 것은

그야말로 오ㅤㅆㅞㅅ~ 입니다 --a

====================

goto에 관한 것은 예외처리시 매우 쓸만하는 것~

유저가 Direction이란 변수를 사용해버리면 문제가 되겠군요.

prefix를 잘 붙여야 할까요?

죠커의 이미지

손님1 wrote:
CN
Quote:
에져 다익스트라는 반복문조차도 필요없는 요소라고 보았습니다. 하지만 현실적인 이유로 (스택의 과도한 사용이나 속도 등의 이유로) 반복문을 사용하는 것을 추천했습니다.

당신이 한 말중에서 당신의 말은 어디있는거요?

당신이 본 글 아래에 있습니다.

익명 사용자의 이미지

프로그래밍 방법론의 변화는 '함수와 변수의 영향 범위를 줄이는 쪽'을 향해 나아간다고 생각합니다.

프로그래밍과 비교될 수 있는 다른 창조물들은, 물리적인 거리에 영향력이 반비레로 점차 감소해 갑니다. 예를들어, 화가가 그림을 그리는데, 캔버스 최하단에 점을 하나 잘못 찍었을때, 그 영향은 캔버스 하단에 쏠리며, 캔버스 상단의 그림에는 비교적 영향이 작습니다.

또 가전 제품의 특정 부품이 말썽이면, 그 부품 주위의 부품들이, 그 부품과 먼 곳에 있는 부품들보다 영향을 크게 받습니다.

하지만 프로그래밍은 그렇지 않습니다.
소스 마지막에 있는 함수 하나 살짝 바꾼 것이, 소스 맨 처음에 위치한 변수에게 큰 영향을 끼칠 수 있습니다. 즉, 다른 창조물들과 달리 거리와 영향력간의 관계가 없기 때문에, '사소한 것 하나가 프로그램을 작동불능으로'만들 수 도 있는 것이죠.

이렇게 영향력과 거리가 반비례하기 때문에, 버그가 생겼을 경우 '버그가 생겼을 만한 원인'을 추측하는 것이 불가능에 가까운 것이 됩니다. 다른 기존의 창조물이라면, 물리적 거리가 가까운 요소들을 살펴보면 되는 것에 비하면 너무나도 힘든 고역이죠.

그래서 프로그래밍은 '개발비용보다 유지 보수 비용이 비싼'놈이 되인 것이죠.

전 '객체지향이 왜 도움이 돼느냐?'고 물으면 위의 이야기를 해주면서 '함수와 변수의 영향 범위를 줄이기 때문'이라고 말합니다.

private 안에 선언된 변수와 함수들의 영향력은 넓다 한들 무조건 해당 클래스 안일테니까요.

전역 변수, goto문을 쓰지 말라는 이유가 여기에 있다고 생각합니다.
전역 변수는 소스 최상부에 선언되지만, 모든 소스에 영향을 끼치며,
goto문은 그나마 '함수'라는 이름으로 묶어놓은 모듈들의 순서를 엉망으로 만들 수 있기 때문입니다.

..--ㅋ

순수 제 생각입니다. 별로 믿을만한 말은 아니기 때문에, 뭔가 이상해도 '이렇게 생각할 수도 있구나'라고 넘어가 주시길 바랍니다.

익명 사용자의 이미지

CN wrote:
moonzoo wrote:
전역변수를 쓰는 기준중 하나는

전역변수가 있다는 사실을 몰라도 무방할 때 라고 봅니다.

간단한 예로 turnLeft() , turnRight() 함수를 통해서

Direction변수를 컨트롤 하는 겁니다. 개발자는 Direction이라는

변수가 있는지 알필요도 없고 변수자체를 추적할 필요도 없습니다.

만약 전역변수의 값을 개발자가 추적하고 이를 조건문등에서

평가해야할 필요가 있다면,

전역변수의 값이 어디서 어떻게 바뀌는지 꿰뚫고 있는다는 것은

그야말로 오ㅤㅆㅞㅅ~ 입니다 --a

====================

goto에 관한 것은 예외처리시 매우 쓸만하는 것~

유저가 Direction이란 변수를 사용해버리면 문제가 되겠군요.

prefix를 잘 붙여야 할까요?

예리한 지적입니다 ^^

Direction변수와 turn~~ 과 같은 관련 함수들을 한 소스파일에

넣고, Direction변수에 static키워드를 주는 것도 고려해 볼 수

있겠네요.

mangg의 이미지

BOOL IsExit = FALSE;
반복문1()
{
   반복문2()
   {
      반복문3()
      {
           if(조건 검사 )
           {
                IsExit = TRUE;
                break;
           }  
      }
      if( IsExit )
        break;
   }
   if( IsExit )
     break;
}


--------------------------------------------------------------------
반복3함수()
{
   반복문3()
   {
       if( 조건 )
         break or return;
   }
}

반복2함수()
{
    반복문2()
    {
        if( 반복3함수() )
          break or return;
    }
}
메인함수()
{
  반복문1()
  {
      if( 반복2함수() )
          break;
  }
}


-----------------------------------------------------------------------------

반복문1()
{
   반복문2()
   {
      반복문3()
      {
           if(조건 검사 )
           {
                goto Exit;
           }  
      }
   }
}
Exit :

위 방법이 아닌 다른 방법좀 갈켜주세요!!!!
자주 코딩때 딜레마에 빠지는 내용이라서.......
더 높은 벽을 보여주심이....

-------------------
나는 Copy&Paster 이다. 나의 화려한 기술 조합에 모두들 나를 두려워 한다. 나도 코드 Maker 이고 싶다.

creativeidler의 이미지

간단한 방법으로 for의 조건절 안에 break 조건을 적을 수 있죠. while이나 do-while을 적절히 활용하는 것도 경우에 따라선 for보다 나을 수 있구요.

violino의 이미지

전역변수를 많이 쓴다고 무조건 나쁘다고 생각지는 않습니다.
물론 프로그래밍에 익숙하지 않아서 넘 전역변수를 남발하면 문제지만,
요즘 C 로 코딩하는 분야라면 서버쪽이나 리얼타임쪽일 가능성이 높은데, 성능도 문제가 되곤 하니깐 필요한 전역변수는 써야겠죠.
제가 예전에 작업하던 프로젝에선 전역변수의 정의를 모두 한 파일에 모아서 혼동을 줄였습니다.
예를들어 ourdef.c 이런 파일에 모든 전역변수 정의를 모아놓고, ourdef.h 에 extern 선언 넣어서 모든 다른 파일들이 참조하도록 만들었죠. 또, 절대 변경되지 않을 참조값이라면, ourdef.h 에 #define 으로 상수 선언하면 되겠죠?
C 에선 많은 다른 파일들 (특히 팀 단위로 작업할 때) 이 공통으로 사용하는 정보를 위해서 전역변수를 쓰는게 유용한 것 같습니다. 예를들어 런타임시에 할당되어서 쓰이는 정보들이 되겠죠. (C++에선 static class를 이용해서 비슷하게 할 수 있죠)
물론 한 파일 안에서만 쓰이는 전역변수라면 위처럼 처리할 필요가 없죠.
위의 어떤분이 말씀하신 매개변수로 넘기는 방법이 유용한 것은 각 변수값에 대한 추적이 용이하기 때문입니다.
전역변수는 언제 어느 놈이 건드릴지 모르기 때문에 유지관리에 각별한 관심을 가져주어야 합니다. 디버깅할때 빼놓지말고 체크해주어야 하고요. 그래서 좀 골치아프긴 하죠.
참고로 매개변수로 넘긴다는 말은 필요한 함수의 프로토타입에 매개변수를 하나 더 선언해줘서 매번 호출할때마다 전역변수로 선언하고 싶은 놈의 값을 그냥 매개변수로 넘겨주는겁니다. 조금 번거롭긴해도 꼭 필요한 전역변수가 아닐때엔 코드가 훨 보기 좋아질겁니다.
(매개변수가 넘 늘어나면 거꾸로 코드의 가독성이 떨어질수도 있습니다)
그럼,

vio:

죠커의 이미지

요즘은 전역변수보다는 싱글톤의 해악이 점점 더 커지고 있지 않은가 하는 생각도 듭니다. 전역변수가 허용되지 않은 몇몇 언어는 전역변수의 용도로 싱글톤이 사용되는 느낌이 듭니다. 역시 사용자가 바뀌지 않는 한 시스템이 바뀌어도 마찬가지가 아닌가 생각도 드네요.

lifthrasiir의 이미지

저도 동의합니다. 싱글톤은 전역변수의 모습을 적절히 감춰서 안 보이게 해 주는 도구라는 생각이 드네요. 싱글톤이라고 생각할 수 있는 객체들도 실제로 리팩토링을 하거나 확장을 하다 보면 싱글톤이 아니어야 하는 경우가 꽤 됩니다. 개인적으로 전역변수나 싱글톤을 꼭 써야 할 경우는 언어 안에서 문법의 확장을 위해 만드는 유틸리티 클래스나, 값이 변할 수 없는 상수 값들(이런 경우 enum이나 뭐 이런 용도로 쓰겠죠) 말고는 별로 없는 것 같습니다.

htna의 이미지

void 반복함수()
{
    struct CFunc {
        static bool NestedFunc(변수1, 변수2, 변수3)
        {
            if(조건검사)
                return false;
            ...
            return true;
        }
    };

    반복문1() 반복문2() 반복문3()
        if( CFunc::NestedFunc(반복변수1,반복변수2,반복변수3) == false )
            return;
}

이런 방법은 어떨지...
정말 이런경우 nested function 이 있었으면 하는 바람이...

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

cppig1995의 이미지

_Bool quit = 0;
for(...; ... && (!quit); ...)
 for(...; ... && (!quit); ...)
  for(...; ... && (!quit); ...)
  {
   ...
   if(...) quit = 1;
   ...
  }

Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.

서지훈의 이미지

아주 옛날 쓰레드이군요 ㅋ
전역 변수는 중간에 변경이 많은 변수라면.. 정말 사용하지 않으시는게 좋으실듯 합니다.
전역 변수를 사용하게 되면 당장은 문제가 없고 편한데...
나중에 소스 분석할 때 아주 골 아픕니다.
전역 변수의 변화를 추적할려면 function call의 순서까지 알아야 가능 한데...
정말 짜증나지 않을 수 없습니다.

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <beer.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.