C로 C++ 흉내내기?

handrake의 이미지

안녕하세요. 실제 프로그래밍에서는 전혀 쓸모가 없을지도 모르는 것이지만 순수히 궁금해서 질문드립니다.
여기 kldp에서도 C로 C++를 흉내낼수 있다는 글을 많이 보았는데요, 어떻게 하면 될지 생각해 보고
나름대로 클래스를 구현해보았습니다.

 
#include<stdio.h>

void *this = 0;
void inc_one();
void dec_one();

typedef void (*void_func)(void);

typedef struct my_str {
        int iLen;
        void_func inc;
        void_func dec;
}my_str;

my_str* init_my_str()
{
        my_str *new_my_str = (my_str*) malloc(sizeof(my_str));
        new_my_str->inc = &inc_one;
        new_my_str->dec = &dec_one;
        new_my_str->iLen = 0;
        return new_my_str;
}

void inc_one()
{
        ((my_str*)this)->iLen++;
}

void dec_one()
{
        ((my_str*)this)->iLen--;
}

main()
{
        my_str *a = init_my_str();
        this = a;
        printf("a->iLen = %d\n", a->iLen);
        a->inc();
        printf("a->iLen = %d\n", a->iLen);
}

여기서 궁금한 점은 저렇게 this=a; 를 매번 지정해주지 않아도 어떤 struct에서 불렀는지
알 수 있는 방법이 있는지 입니다. 이렇게 하는것보다 더 좋은 방법이 있으면 제시해 주시면 고맙겠습니다 ^^

keizie의 이미지

GTK+ 2.x에서부터 도입된 GObject 구조를 보시면 어떤 건지 감이 올 겁니다.

C로 OOP의 각 개념을 잘 구현했습니다.

hyperhidrosis의 이미지

this 를 전역으로 하면 this 의 의미가 없어집니다...

그래ㅅ

a->func(a, param);

과 같이 매번 this 로 사용할 object 를 파라메터로 같이 보내주는
방식을 사용하고는 합니다.

skyul의 이미지

hyperhidrosis wrote:
this 를 전역으로 하면 this 의 의미가 없어집니다...

그래ㅅ

a->func(a, param);

과 같이 매번 this 로 사용할 object 를 파라메터로 같이 보내주는
방식을 사용하고는 합니다.

자바의 C 인터페이스인 JNI(Java Native Interface)도 비슷한 방법으로 this나 class instance를 넘깁니다.

--
서광열 소프트웨어 블로그: http://skyul.tistory.com 입니다.

alwaysN00b의 이미지

C로는 this를 계속 넘겨주는걸로 알고 있습니다.

void foo1(my_str *THIS) 
{ 
        printf("it's %d.\n",THIS->iLen);
} 

언제나 시작

corba의 이미지

C++에서도 내부적으론 this를 파라미터로 넘기고 있는 걸로 압니다.

foo->bar();는

내부적으로

bar(foo);

라고 생각하면 되실 듯 합니다.

ㅡ,.ㅡ;;의 이미지

딴지일지 모릅니다만..
머하러 어렵게 C로 C++ 흉내냅니까... 그냥 C++ 사용하면되지..
C++ 흉내냈다고 해봤자 C++ 같지도 않구요..
C로는 그냥 C 처럼 짜는것이 가장 자연스럽습니다.

누가 그런코드로 짜놓은 소스가 있는데요..
보면 소스다지우고 싶습니다..^^;
메모리 오류도 많을뿐만아니라 메모리 할당해제도 재대로 안되있거든요..함수재사용은 매우안되고 있고..
문제는 오류를 잡아내기 무척힘듭니다.또한속도 무지 늦고..
시스템 리소스 엄청많이먹네요..

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ


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

익명 사용자의 이미지

ㅡ,.ㅡ;; 님이 작성하신 글을 다 지우고싶네요.

나는오리의 이미지

ㅡ,.ㅡ;; wrote:
딴지일지 모릅니다만..
머하러 어렵게 C로 C++ 흉내냅니까... 그냥 C++ 사용하면되지..
C++ 흉내냈다고 해봤자 C++ 같지도 않구요..
C로는 그냥 C 처럼 짜는것이 가장 자연스럽습니다.

누가 그런코드로 짜놓은 소스가 있는데요..
보면 소스다지우고 싶습니다..^^;
메모리 오류도 많을뿐만아니라 메모리 할당해제도 재대로 안되있거든요..함수재사용은 매우안되고 있고..
문제는 오류를 잡아내기 무척힘듭니다.또한속도 무지 늦고..
시스템 리소스 엄청많이먹네요..

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

C++은 덩치가 크지요.
C로만 구현해야 하는 곳이 있고, 그런 곳에서 C++의 좋은 기능(장점)을 구현할 수 있다면(취한다면) 하는게 좋은것이지요.
umean2me의 이미지

C로 C++형식의 코딩을 경험하였습니다. C++이 상식적으로 덩치가 크나 설계방법에 따라 C보다도 더 적고 심플하게 할 수도 있지요.

C++이 아닌 OOP는 C수준에서도 얼마든지 적용 가능하다고 생각합니다. 이전 프로젝트에서 서버의 Reactor패턴을 적용하여 C로 프레임웍을 작성하였었는데 정말 깔끔하고 코드도 보기 좋았습니다. 물론 유지보수도 상당히 쉬웠고 시간상 앞에서 C로 주무르던 코더들보다도 시간상 3배 이상 빨리 끝내기도 했습니다.(결과적으로 OOP를 적용한 저와 제 옆사람만 제 일정에 끝냈습니다.)

OOP는 다른것처럼 '무작정 따라하기' 씨리즈를 흉내내서는 안되는 물건이라고 생각합니다.

얼마나 거대한 프로그램을 할지는 모르겠습니다. 하지만 빵빵한 하드웨어와 빵빵하다 못해 다 쓰지도 못하는 메모리를 두고서 C++이 느리고 유지보수가 어렵다는 억측(?)으로 매도하는 것은 좀 곤란합니다. 게다가 쓰레드를 사용한다면 쓰레드적용에 대한 것을 유지하기에 C++만큼 개념과 코딩을 일치시키는 것 또 한 C보다도 엄청나게 쉽죠.

외국에서 20년 가까이 연구하고 책쓰고 적용하고 하는것 자체를 바보라서 하는걸까요? 그들이 정신이 나가서 그런 얼토당토 안한것을 20년 가까이 연구하고 실무에 적용했다고 생각이 드시나요....쩝~

다른 몇몇분들께서 C답게 짠다는것이 어떤건지 잘 모르겠습니다. 여기저기 만들어 놓은 함수와 전역변수로 도배해 놓아 함수데로 점프점프~해가는것이 C답게 만든다고 하시는건지...아니면 리눅스의 커널처럼 C로 C++의 가상함수처럼 한다든가 하는-(리눅스 커널속에 묻어 있는 OOP적 개념들이 적용되어 있다는걸 살짝살짝 보십시요. 뭐..OOP적 개념이라기보다 패턴이라 봐야 되겠지만..특히나 VFS같은거요..)-전체에 걸쳐있는 개념들을 보고 C답다고 하시는지..

C가 C답다라는 것이 아니라 얼마나 개념적으로 잘 정의되어, 유연성있게, 또는 확장성있게 설계되었느냐에 따라 프로그램의 성패가 갈리는 것이지 C답다라는 것은 전혀 엉뚱한 답변인것 같습니다.

C 자체는 무안합니다. 한때 C++컴파일러들은 C++코드를 C로 바꾸어 컴파일하곤 했었습니다. 그러니 OOP 경험이 없는 상황에서 이렇다 저렇다 말씀하시는 것은 매우 곤란해 보이네요..

kalstein의 이미지

C++은 C보다 조금은 덩치가 클지도 모릅니다. 그러나....
덩치가 10% 늘어나고 (사실 10%도 안됩니다만...) 유지보수, 개발의 편의성이 200%가 됩니다 -_-;;;
다만 OOP의 개념없이 그냥 만들게되면 C++은 괜한 덩치만 큰, 생성자와 복사오퍼레이션 등으로 오버헤드만 있는 언어에 불과하게 되겠지요.

단점이 있다면....컴파일러를 만들기가 좀 어렵죠 ^^;;;; (C보다는) 그점을 제외하면 글쎄요. C++이 나쁠 이유는 전혀없습니다. 똑같은 프로젝트 시행시에 C++과 C로 진행한다면 어느쪽이 월등한 코드 퀄리티와, 짧은 기간을 지닐지는 거의 뻔하죠. (동 레벨의 프로그래머가 짠다면요.)


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

hyperhidrosis의 이미지

c++ 이 c 보다 무겁다는 말은 수긍할 수 없습니다.

가볍게 만드는것을 목표로 코딩한 c++ 은 c 와 같거나 더 가볍게 짤 수 있습니다.

( 코드의 양, 바이너리의 크기, 실행속도 측면 )

cdpark의 이미지

corba wrote:
C++에서도 내부적으론 this를 파라미터로 넘기고 있는 걸로 압니다.

foo->bar();는

내부적으로

bar(foo);

라고 생각하면 되실 듯 합니다.

C++의 확장안 중에 이런 아이디어도 있습니다.

func(arg1, arg2, ...)와 arg1.func(arg2, ...) 를 아예 같은 것으로 인식하게 하자는거죠. 따지고보면 굳이 구분해야 할 필요도 없고요. 그러면 외부 함수도 쉽게 member function처럼 보이게 코딩할 수 있게되죠.

alwaysN00b의 이미지

ㅡ,.ㅡ;; wrote:
딴지일지 모릅니다만..
머하러 어렵게 C로 C++ 흉내냅니까... 그냥 C++ 사용하면되지..
C++ 흉내냈다고 해봤자 C++ 같지도 않구요..
C로는 그냥 C 처럼 짜는것이 가장 자연스럽습니다.

누가 그런코드로 짜놓은 소스가 있는데요..
보면 소스다지우고 싶습니다..^^;
메모리 오류도 많을뿐만아니라 메모리 할당해제도 재대로 안되있거든요..함수재사용은 매우안되고 있고..
문제는 오류를 잡아내기 무척힘듭니다.또한속도 무지 늦고..
시스템 리소스 엄청많이먹네요..

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

http://bbs.kldp.org/viewtopic.php?t=33892&highlight=%BD%BA%C6%C4%B0%D4%C6%BC+gtk

한번 읽어보시길 바랍니다.

OOP의 캡슐화라..... OOP의 기본 개념이 뭔지 다시 찾아봐야겠네요.

언제나 시작

ㅡ,.ㅡ;;의 이미지

몇몇분들이 제글에대해 반론을 제기하셨는데

C적인것은 C문법이 적용되는 모든것이 C 적일수있죠..
즉 C로 가장 효율좋고 편리하게 작성하면 그것이 바로 C적이라봅니다....

제가말하는 하지말자고 했던것은 억지로 C++ 흉내내면 안좋다는것이죠..
구조체내부에 함수포인터 넣어다고 이것이 C++ 일까요..
그것도 C고 모두 C 일뿐입니다. 다만 간단히 해도될것을 억지스럽게 모양만 C++ 흉내낸답시고 그러지말라는것이죠.
드물게 그런사람존재합니다.


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

ㅡ,.ㅡ;;의 이미지

alwaysN00b wrote:
ㅡ,.ㅡ;; wrote:
딴지일지 모릅니다만..
머하러 어렵게 C로 C++ 흉내냅니까... 그냥 C++ 사용하면되지..
C++ 흉내냈다고 해봤자 C++ 같지도 않구요..
C로는 그냥 C 처럼 짜는것이 가장 자연스럽습니다.

누가 그런코드로 짜놓은 소스가 있는데요..
보면 소스다지우고 싶습니다..^^;
메모리 오류도 많을뿐만아니라 메모리 할당해제도 재대로 안되있거든요..함수재사용은 매우안되고 있고..
문제는 오류를 잡아내기 무척힘듭니다.또한속도 무지 늦고..
시스템 리소스 엄청많이먹네요..

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

http://bbs.kldp.org/viewtopic.php?t=33892&highlight=%BD%BA%C6%C4%B0%D4%C6%BC+gtk

한번 읽어보시길 바랍니다.

OOP의 캡슐화라..... OOP의 기본 개념이 뭔지 다시 찾아봐야겠네요.


개념을 다시 찾아보라구요? 무슨개념요?
제가생각하고 있는것과 님이 생각하는것이 다르단말씀인가요?
무엇이 다른지 말씀해주세요.. 제가들어보고 정말 잘못알았다면 사과드리죠..
님이 정말 무엇을두고 하는말씀인지 몰라서 그렇습니다.


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

ironboy의 이미지

Berkeley DB(http://www.sleepycat.com ) 라이브러리를 사용하는 모습도
C로 C++처럼 쓰는 모습일 껍니다.

그 라이브러리를 사용하는 모습을 봐도
handrake님이 예를 들어 놓은 것 처럼,
결국은 계속 this를 넘기더군요.

C로 C++개념(OOP?)을 구현하기 위해, 어느정도의 문법적 불편함은
감수하셔야 할 듯 하네요.

익명 사용자의 이미지

ㅡ,.ㅡ;; wrote:
alwaysN00b wrote:
ㅡ,.ㅡ;; wrote:
딴지일지 모릅니다만..
머하러 어렵게 C로 C++ 흉내냅니까... 그냥 C++ 사용하면되지..
C++ 흉내냈다고 해봤자 C++ 같지도 않구요..
C로는 그냥 C 처럼 짜는것이 가장 자연스럽습니다.

누가 그런코드로 짜놓은 소스가 있는데요..
보면 소스다지우고 싶습니다..^^;
메모리 오류도 많을뿐만아니라 메모리 할당해제도 재대로 안되있거든요..함수재사용은 매우안되고 있고..
문제는 오류를 잡아내기 무척힘듭니다.또한속도 무지 늦고..
시스템 리소스 엄청많이먹네요..

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

http://bbs.kldp.org/viewtopic.php?t=33892&highlight=%BD%BA%C6%C4%B0%D4%C6%BC+gtk

한번 읽어보시길 바랍니다.

OOP의 캡슐화라..... OOP의 기본 개념이 뭔지 다시 찾아봐야겠네요.


개념을 다시 찾아보라구요? 무슨개념요?
제가생각하고 있는것과 님이 생각하는것이 다르단말씀인가요?
무엇이 다른지 말씀해주세요.. 제가들어보고 정말 잘못알았다면 사과드리죠..
님이 정말 무엇을두고 하는말씀인지 몰라서 그렇습니다.

쓰레드를 만드신분이 C로 OOP를 구현하는 이유가 단지 '흉내' 뿐이라해도 '절대' 하지 말자고 하신 이유를 모르겠습니다.

Quote:
OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

OOP의 캡슐화가 틀린것인가요? C로 캡슐화 하는것이 틀린것인가요?
제가 내공이 부족하여 OOP개념을 다시 ㅤㅊㅏㅊ아볼려고 한것이지 ㅡ,.ㅡ;;님에게 다시 찾아보라고 한적은 없습니다.
Quote:
OOP의 캡슐화라..... OOP의 기본 개념이 뭔지 다시 찾아봐야겠네요.

그리고, C++을 이용하면서도 충분히 C++같지 않은 프로그램도 있습니다.
ㅡ,.ㅡ;; 님이 말씀하신 'C는 그냥 C처럼 짜는 것이 자연스럽다' 에서 C가 어떤게 자연스러운지 모르겠습니다.

Quote:

C = 구조적 프로그램
C++ = 객체지향적프로그램

위 인용이 틀린이유는 링크걸어 놓은 쓰레드로 충분히 설명될거라 믿습니다.
alwaysN00b의 이미지

로그인을 안해서 수정이 안되네요... 쩝.
위 댓글중 마지막에 제가 하고자 했던 말은 C로도 OOP를 구현할수 있고, C++로도 구조적 프로그램을 할수 있습니다. 물론 C++로 하면 OOP구현이 쉽지만, C로도 충분히 깔끔하게(소스 보기가 깔끔하다는 뜻은 아닙니다) 구현할 수 있습니다.

언제나 시작

creativeidler의 이미지

이 쓰레드가 은근히 긴 생명력을 자랑하는군요-_- 차라리 이럴 땐 코드로 한 판 붙어보는 게 어떨까요? 모두가 합의할 만한 문제 하나를 내고 각자 자신의 주장대로 코딩을 하는 겁니다. 그러고 나서 코드를 비교해 보는 거죠. 물론 그 비교 역시 주관적이겠지만 지금처럼 말로만 하는 것보다는 훨씬 나을 것입니다.

참가하고 싶은 분이 두 분 이상 되면 문제는 제가 만들어 보겠습니다. OOP적 개념이 있으면 쉽게 해결할 수 있는 그런 문제를 C를 C처럼(?) 써서 해결하는 코드, C를 C++처럼 써서 해결하는 코드, C++로 해결하는 코드, 비교해보면 좋지 않겠습니까? 기왕이면 정통파 OOP 언어인 자바나 스몰토크, 파이썬 등으로 된 코드랑 C 패밀리와의 비교도 해보면 재미 있을 것 같구요.

자자, 프로그래머는 코드로 말합니다. 자신의 주장을 코드로 증명해봅시다.

배추의 이미지

c로 java 흉내내는 것이 더 나을것 같습니다.
아님 c python 조합도.

제아이디와비번은 배추, 12ws 입니다.

hyperhidrosis의 이미지

Quote:
자자, 프로그래머는 코드로 말합니다. 자신의 주장을 코드로 증명해봅시다.

짱입니다(==공감합니다). 문제 내주세요.
umean2me의 이미지

ㅡ,.ㅡ;; wrote:

구조체내부에 함수포인터 넣어다고 이것이 C++ 일까요..
그것도 C고 모두 C 일뿐입니다. 다만 간단히 해도될것을 억지스럽게 모양만 C++ 흉내낸답시고 그러지말라는것이죠.
드물게 그런사람존재합니다.

아직도 잘 이해를 못하시는 군요. 님께서 알게모르게 사용하시는 표준 라이브러리 안에서도 C++처럼 보이는것들이 존재합니다. 대표적인것으로 FILE 식별자가 존재하지요. 님께서 사용하시면서도 그 개념이나 의미를 잘 파악 못하시는 것 같은건 아닌지요.

'어떠한 문제를 지역화하는 것'-(더 이쁜말이 있던데 기억이...) 은 이미 오래전부터 존재하던 개념들(모듈화,플러그인,라이브러리개념, 프레임웍개념등도..)이고 그것을 코딩수준의 문법적으로 정의해 놓은 언어들이 C++이나 자바죠. OOP란 놈이 어느날 떵~하고 나타난게 아닙니다. C로 짜더라도 문제를 지역화하는 것은 꾀나 바람직한 방법이라고 보입니다.-(DB라이브러리라던가 그래픽 라이브러리라던가 하는것 자체도 지역화하는 것이죠. 국내에서 C로 하더라도 그런 룰과 개념을 적용하여 프로그래밍 하는 업체는 제 눈으로 확인한건 겨우 몇건에 불과했습니다.)-그것은 유지/보수에도 탁월하죠. 이해를 못하신다면 다른것들을 좀 더 경험하셨으면 좋겠군요.

아무튼...이러한 여러 경험, 설계등의 과정을 거치다 보니 불편한 것들을 해결하려는 의지에서 나온것들이라고 보여집니다.

ㅡ,.ㅡ;; wrote:
몇몇분들이 제글에대해 반론을 제기하셨는데
C적인것은 C문법이 적용되는 모든것이 C 적일수있죠..
즉 C로 가장 효율좋고 편리하게 작성하면 그것이 바로 C적이라봅니다....

제가말하는 하지말자고 했던것은 억지로 C++ 흉내내면 안좋다는것이죠..


C가지고 C++을 흉내내면 더 흉하다고요? 어설픈 C++지식가지고 C++ 코딩을 하게되면 흉한것은 마찬가지입니다. 하지만 C로도 C++ or OOP 적으로 바람직하게 또는 아름답게 코딩이 가능하다면 어떻게 하시겠습니까? 이미 여러 공개소스를 통해서도 앞서 말한 문제에 대한 지역화를 통해 OOP처럼 보이는 것들은 보실 수 있습니다. 님께서 쓰는 공개 라이브러리들 조차 그런것들 이지요.

제 개인적 주관입니다만 C문법을 적용하여 아무리 프로그램이 잘 돌아간다 하여 그것이 아무도 못 알아 볼만큼 수준의 코딩이라면 C답다라고 부르지 않습니다. 이런것 조차 C답다라고 하시겠습니까?게다가 편리하다고 무작정 쓰는 전역변수...이것 또한 제 스스로는 C답다라고 생각하지 않는 부분입니다. 집의 화장실 스위치를 편리하다고 벽 여기저기 다 붙어놓는것과 같은 이치죠.

제가 볼때 국내의 SI들의 설계 수준은 정말 형편없습니다. 이거 발로 짠거 아닌가 싶을 정도입니다.

4-5 깊이로 함수를 호출하는건 예사이며 전역변수 사용하는것은 정말 대수롭지 않게 보고 있죠. 이 상황에서 전역변수들에 대한 문서를 가정하여 봅시다. 코드길이는 전체 1만라인 이상입니다. 어떻게 문서화를 또 상대방에게 이해시킬것인지...이런 상황은 새로 만드는것 보다 인수인계의 과정이 더 길어지는게 다반사 입니다. (인수인계..이게 포인트라고 생각됩니다..)

쓰레드라는 것은 엄두도(?) 못내는 실정입니다. 이런 시스템하에서 얼마나 상위 품질의 솔루션을 내놓겠습니까. 아무리 인력이 많아도 특정 집단을 제외하고는 이렇다할 솔루션들을 못내놓는게 국내 현실 아닙니까. 하다 못해 정말 라이브러리다운 라이브러리를 가지고 있는 업체는 몇%나 될까요..

원하신다면 제가 C로 C++적으로 적용했던 일부 코드를 보여드리겠습니다.

ㅡ,.ㅡ;;의 이미지

Anonymous wrote:

Quote:
OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

OOP의 캡슐화가 틀린것인가요? C로 캡슐화 하는것이 틀린것인가요?

OOP의 캡슐화가 틀렸다는것이 아니라 OOP의 캡슐화여 장점을 살려야하는데 이건 오히려 캡슐을 까봐야할실정되버렸다는것이죠..
C로 했기때문이 아니라 까봐야하는 오히려 불편하게 변하는 흉내내기에 지나지 않는것은 하지말자고 말했던거죠.

Quote:

그리고, C++을 이용하면서도 충분히 C++같지 않은 프로그램도 있습니다.
ㅡ,.ㅡ;; 님이 말씀하신 'C는 그냥 C처럼 짜는 것이 자연스럽다' 에서 C가 어떤게 자연스러운지 모르겠습니다.
Quote:

C = 구조적 프로그램
C++ = 객체지향적프로그램


C가 구조적이고 C++만 객체지향적이다..
미묘한말의차이죠..
어떤것이 자연스럽냐.. 매우포괄적이고 설명하기 힘들군요..
그러니까.. 자연스럽게.. 물흐르면흐르는데로..뷁...
짜는것이 가장 C같겠죠..

객체지향 즉.. 객체를 무엇으로 보느냐도 문제겠지만..만일
C에서도 객체가 필요하다면 그것을 만드는것이 자연스런일이죠..
그리고 옛날부터 C++이생기기전부터 그것이 필요하면 그렇게 구현해왔지 않겠어요? 언제부터인가 OOP말이나오면서 마치 그것은 C에서 하지 않는것으로 몰아가는듯한분위기? 인데 ...
문제는 그것이 그리 많이 필요하지 않다는거죠..
그런데 억지 스럽게 모든것을 그틀에 끼워맞추려한다면..
그것이 부자연스럽다는겁니다.
또한 클레스에서 데이터부가 없다해서 객체가 아닐까요..
또한 함수가 없다하여 객체가 아닐까..
C의 구조체와 함수와의 차이또한 없는것이 아닐까요..
머 두서 없이 썻습니다만..
제가 C는 C처럼이란말에 잘못되었다고 생각하시는분들은 도데체 C처럼을 어떻게 생각하시길래 그렇게 생각하는지 그게 의문입니다.전 그걸알수가 없네요..

누가 위에 구체적인 코딩의 예로 들면 좋을것같다고 했습니다만..
예를들자면..

그냥 아주단순히 메모리가필요 했습니다...
중간에 사라져야할이유도 크기가 조정되어야할이유도 없는...
저같으면 오토변수로 잡겠습니다만..

궂이 구조체를 선언하고 그내부에 함수포인터로 메모리할당함수를 정의하고 또 그멤버포인터편수에 다시 구조체를 연결하고 그구조체에 메모리를할당하게한다면...
좀어색하다는거죠..
문제는 오히려 성능저하를 시키는데도 말이죠..
제가 말하는건 이런것이었습니다. 오히려 성능저하에 보기도 힘들고 코딩양도 많아지는것을 고집스럽게 그렇게 하는건....안좋다고 봅니다.


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

ㅡ,.ㅡ;;의 이미지

umean2me wrote:
ㅡ,.ㅡ;; wrote:

구조체내부에 함수포인터 넣어다고 이것이 C++ 일까요..
그것도 C고 모두 C 일뿐입니다. 다만 간단히 해도될것을 억지스럽게 모양만 C++ 흉내낸답시고 그러지말라는것이죠.
드물게 그런사람존재합니다.

아직도 잘 이해를 못하시는 군요. 님께서 알게모르게 사용하시는 표준 라이브러리 안에서도 C++처럼 보이는것들이 존재합니다. 대표적인것으로 FILE 식별자가 존재하지요. 님께서 사용하시면서도 그 개념이나 의미를 잘 파악 못하시는 것 같은건 아닌지요.

제말을 오해하시는군요.. 제가 알게 모르게 사용하는 님이말씀하신 표준라이브러리 안에도 C++처럼 보이는것을이 존재하는것이 아니라 그것이 가장자연스러운 C 처럼 보입니다..
님은 원래 C의 구현방법이었던것을 마치 C++만의 것인양 말씀하시는건 아닌지요..
님은 마치 C와 C++의 특정한구역을 정해두고 서고의 경계를 지나면.. 침범했다고 생각하시는데 그렇지 않다는거죠..
무엇이 C 적이고 무엇이 C++적입니까.. 오히려 제가 묻고 싶군요..
조금넘어갔다고 그것이 C가 C++적인것을 사용한것입니까? 아니죠..오히려그건자연스런일입니다.

예를들어 보죠..
늑대가 산에살다가 가끔강에내려가 수영도하고 물도먹었습니다.
이것이 늑대가 물개흉내낸것일까요?
마찬가지로 물개가 물에서 나와 바위위에서 잠을잤습니다.
이건 물개가 늑대흉내낸것일까요..
둘다자연스런거죠..
다만.. 물개가 아예 산꼭대기 올라가 산다거나..
늑대가 가예 태평양한가운데가서 살겠다고 가는짓은 하지마라는거였습니다.
그런데 님은 그것을 그러다면 늑대가 수영도하고 물도먹는데.
이것이 다 잘못되었냐고 따지는격입니다.

또한 그(늑대도 수영하고 물을먹는다는)핑계로 늑대가 태평양한가운데로 가는것을 정당화 할수는 없는것입니다.


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

corba의 이미지

ㅡ,.ㅡ;;님께서 전달하려시는 메세지는 이해가 되지만 처음 올리신 글에 오해의 소지가 다분합니다. :D

ㅡ,.ㅡ;;의 이미지

umean2me wrote:
원하신다면 제가 C로 C++적으로 적용했던 일부 코드를 보여드리겠습니다.

님만 괜찮으시다면 저야 100번 좋죠 소스유출되지 않는범위내에서 맛보기 정도라면말이죠..


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

ㅡ,.ㅡ;;의 이미지

corba wrote:
ㅡ,.ㅡ;;님께서 전달하려시는 메세지는 이해가 되지만 처음 올리신 글에 오해의 소지가 다분합니다. :D

글쎄요.. 애초에 이글이 흉내내기..였기때문에..
흉내.. 이건 아니라고 생각했죠.. 필요한것(곳) 이라면.. 그것이 왜.. 흉내일이유가 전혀없죠.. 오히려 고유권한? 것이었던거죠.. :?


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

umean2me의 이미지

ㅡ,.ㅡ;; wrote:

제말을 오해하시는군요.. 제가 알게 모르게 사용하는 님이말씀하신 표준라이브러리 안에도 C++처럼 보이는것을이 존재하는것이 아니라 그것이 가장자연스러운 C 처럼 보입니다..
님은 원래 C의 구현방법이었던것을 마치 C++만의 것인양 말씀하시는건 아닌지요..
님은 마치 C와 C++의 특정한구역을 정해두고 서고의 경계를 지나면.. 침범했다고 생각하시는데 그렇지 않다는거죠..
무엇이 C 적이고 무엇이 C++적입니까.. 오히려 제가 묻고 싶군요..
조금넘어갔다고 그것이 C가 C++적인것을 사용한것입니까? 아니죠..오히려그건자연스런일입니다.

이건 제가 하고 싶던 이야기입니다...ㅜㅜ
C++처럼 보이는것들이라는 표현은 C만을 고집하시는 분들의 이해를 돕기위해 사용된 말뿐이죠...그래서 앞뒤로 '어떠한 문제의 지역화' 라는 말로 표현했던 겁니다. 이해의 안에서 작성하려 했기 때문에 그렇게 보일 수도 있겠군요.

C에서는 안보이는 C++의 특징이 있습니다. C에서도 보일라나요? 몇몇? 등등의 C++라이브러리? 들은 최적화된 디자인을 고의적으로 유도하기도 합니다. C에서는 그러한 모습들이 보이지 않는다는 겁니다. C++은 사용자로 하여금 설계의 중요성을 마치 유도하는것처럼 보입니다. 아니면 실제로 유도하고 있던가요..

그러나 C문법 자체의 성질은 그러한 성질이 업죠. 이러한 부분 때문에 C만을 고집하는 분들은 그런 설계의 중요성을 무시 하는걸 많이 볼 수 있는데요. 그것을 두고 C답다라는 것에 대해 몇번을 걸고 넘어진거란걸 알아주셨으면 좋겠습니다.

아르아의 이미지

결국엔 다들 결론은
"C로도 잘 짤 수 있으면 잘 짜자. 괜히 삽질하지 말고" :twisted:
이거 아닌가요.
더이상의 이야기는 마치
"유도가 쎄나요 무에타이가 쎄나요?"를 두고 으르렁 어흥 거리는것과 비슷하다고 봅니다.
물론 "세미슐츠(K1짱먹고 있는분)와 효도르(프라이드 짱먹고 있는분)가 붙으면
누가 이길까요?" 뭐 이런게 재미있는 주제이긴 하지요. 저도 궁금하고요

그런의미에서 저는 계산프로그램을 짤때 포트란,C를 두고
왜 C++로 짜느냐 하는게 참 궁금합니다.
구체적인 예(성공적인 사례나 계산프로그램인데도 OOP로 짤 수밖에 없는경우)
를 알고 싶어요 :)

익명 사용자의 이미지

ㅡ,.ㅡ;; wrote:

객체지향 즉.. 객체를 무엇으로 보느냐도 문제겠지만..만일
C에서도 객체가 필요하다면 그것을 만드는것이 자연스런일이죠..
그리고 옛날부터 C++이생기기전부터 그것이 필요하면 그렇게 구현해왔지 않겠어요? 언제부터인가 OOP말이나오면서 마치 그것은 C에서 하지 않는것으로 몰아가는듯한분위기? 인데 ...
문제는 그것이 그리 많이 필요하지 않다는거죠..

C++이 생기기 이전부터 OOP개념은 있었습니다.
OOP는 패러다임 입니다. 생각의 관점의 변화이죠.
OOP를 쉽게 구현할수 있는 언어가 많이들 알고 계시고 대표적인 C++과 JAVA입니다.

JAVA나 C++이 나오고 OOP가 나온것이 아니고, 소프트웨어를 개발하면서 코드의 재사용(등)이 절실해지면서 기술이 발달해가는 것입니다.

아마 C++이 나오기 이전에 C로 OOP를 구현했을 것입니다.

흔히들 우리나라 개발자 대부분이 지식구조가 마름모꼴이라는 말을 들은 적이 있습니다.
C로 OOP를 구현해보면 C++을 사용할때 얼마나 편한가를 더욱 크게 느낄수 있을것입니다. '절대' 하지말아야 할것이 아니고, 해보면 크게 도움이 되는것입니다.

마소에 이런(비슷한) 말이 실린적이 있었죠.
'프로그래머는 그 귀차니즘 때문에 밤을 세워 연구한다.'
C로 OOP구현하기가 귀찮으니깐 C++을 개발했다 생각합니다.

아직 내공이 부족하니 태클 환영합니다.

doldori의 이미지

김지훈 wrote:
그런의미에서 저는 계산프로그램을 짤때 포트란,C를 두고
왜 C++로 짜느냐 하는게 참 궁금합니다.

편하니까요. :-) 예를 들어 C로 행렬 연산 프로그램을 만들 때 거의 똑같은 코드인데도
float와 double용을 따로 만들다 보면 이게 무슨 짓인가 하는 생각이 들지요.
(포트란도 사정은 비슷할 듯 합니다.) 이런 경우 C++의 템플릿을 쓰면 정말 편하죠.
템플릿을 쓴다고 성능이 저하되는 것도 아니고요.
연산자 오버로딩도 코딩의 편의성이나 가독성을 크게 증진시킬 수 있습니다.

김지훈 wrote:
구체적인 예(성공적인 사례나 계산프로그램인데도 OOP로 짤 수밖에 없는경우)
를 알고 싶어요 :)

oonumerics.org
이 중의 많은 라이브러리가 템플릿을 쓰고 있군요.
익명 사용자의 이미지

creativeidler wrote:
이 쓰레드가 은근히 긴 생명력을 자랑하는군요-_- 차라리 이럴 땐 코드로 한 판 붙어보는 게 어떨까요? 모두가 합의할 만한 문제 하나를 내고 각자 자신의 주장대로 코딩을 하는 겁니다. 그러고 나서 코드를 비교해 보는 거죠. 물론 그 비교 역시 주관적이겠지만 지금처럼 말로만 하는 것보다는 훨씬 나을 것입니다.

참가하고 싶은 분이 두 분 이상 되면 문제는 제가 만들어 보겠습니다. OOP적 개념이 있으면 쉽게 해결할 수 있는 그런 문제를 C를 C처럼(?) 써서 해결하는 코드, C를 C++처럼 써서 해결하는 코드, C++로 해결하는 코드, 비교해보면 좋지 않겠습니까? 기왕이면 정통파 OOP 언어인 자바나 스몰토크, 파이썬 등으로 된 코드랑 C 패밀리와의 비교도 해보면 재미 있을 것 같구요.

자자, 프로그래머는 코드로 말합니다. 자신의 주장을 코드로 증명해봅시다.

-,.- 하고 umean2me 님하고 코드작성해주세요! ;;;

umean2me의 이미지

ㅡ,.ㅡ;; wrote:
umean2me wrote:
원하신다면 제가 C로 C++적으로 적용했던 일부 코드를 보여드리겠습니다.

님만 괜찮으시다면 저야 100번 좋죠 소스유출되지 않는범위내에서 맛보기 정도라면말이죠..

코딩은 해당업체에 룰을 따랐습니다. 헤더만을 올려놓습니다. 소스는 쫌...엉망입니다...앞서 이야기 했던 네트워크처리를 위한 부분입니다.

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************
 DISPATCHER			: Dispatcher 식별자
 size_t size		: 현재 등록되어 있는 fd 수
 size_t maxfds		: 최대 등록 가능한 fd 수(필요에 따라 수시로 증가)
 pollFDs			: 현재 사용하고 있는 struct pollfd 구조체 포인터
******************************************************************************/
typedef struct
{
	size_t size;
	size_t maxfds;
	struct pollfd *pollFDs;
} DISPATCHER;

/******************************************************************************
 Dispatcher_Create(const size_t maxfds)
 Dispatcher_Create는 calloc를 통해 DISATCHER구조체를 생성하고 생성된 구조체를
 반환한다.
******************************************************************************/
DISPATCHER *Dispatcher_Create();


/******************************************************************************
 Dispatcher_Destroy(DISPATCHER *dispatch)
 Dispatcher_Create를 통해 생성된 구조체를 free를 통해 소멸시킨다.
******************************************************************************/
void Dispatcher_Destroy(DISPATCHER *dispatch);


/******************************************************************************
 Dispatcher_Add(DISPATCHER *dispatch)
 DISPATCHER의 식별자에 fd를 추가함으로써 poll이 fd를 감시할 수 있도록 한다.
******************************************************************************/
int Dispatcher_Add(DISPATCHER *dispatch, const int fd);


/******************************************************************************
 Dispatcher_Del(DISPATCHER *dispatch)
 DISPATCHER의 식별자에 fd를 삭제함으로써 poll이 fd를 감시에서 제거한다.
******************************************************************************/
int Dispatcher_Del(DISPATCHER *dispatch, const int fd);


/******************************************************************************
 Dispatcher_Wait(DISPATCHER *dispatch, const long timeout)
 등록된 fd들을 감시한다. 또 한 이 함수를 사용한 시점에서는 Block되며 이벤트
 가 발생할때까지 대기하게 된다. timeout으로 대기시간을 설정하게 되면 대기시
 간 이후에 함수를 빠져나가게 된다. 대기시간은 밀리세컨드이다.
******************************************************************************/
int Dispatcher_Wait(DISPATCHER *dispatch, const long timeout);


/******************************************************************************
 Dispatcher_CurfdsSize(DISPATCHER *dispatch) 
 DISPATCHER 에 현재까지 추가된 소켓의 수를 반환한다.
******************************************************************************/
size_t Dispatcher_CurfdsSize(DISPATCHER *dispatch);

#ifdef __cplusplus
}

poll을 객체형식으로 만들어 놓은겁니다. poll의 지저분한(?) 고유 코드는 다 빠지고 이것만으로 하니 별 신경쓸께 없었습니다. 위의 함수군을 사용하는 일은 다른 사람은 없었습니다. 이것은 밑의 Reactor을 만들기 위해 만들어 놓은 것이죠. 써도 별상관 없겠지만 이걸 익히려 노력은 안하리라 생각했기 때문입니다.

다음은 Reactor패턴을 C수준에서 응용한겁니다. 더 세밀히 하자면 함수포인터를 사용해야 했으나..그럴만한 시간적..ㅜㅜ..

Client Handler(CHandler)는 접속된 각각의 개별 커넥션을 말합니다. 그리고 이것들의 이벤트를 관리하며 처리하는 Reactor이 존재합니다. 사용자는 CHandler의 이벤트 발생시에 처리할 부분을 작성하게 됩니다. 즉 비지니스 로직이 들어갑니다.

Reactor은 TCPCLIENT 객체를 추가하게 되면 CHANDLER(Client Handler)를 생성하게 됩니다. 그리고 CHandler_*함수를 각 이벤트 분류에 따라 호출하게 해줍니다. '유저가 작성해야할 함수' 가 가상함수부분인데...여하튼 이 부분을 사용자가 작성해야 전체가 완성됩니다. 이 부분은 비지니스 로직이 들어가야할 부분이죠. 이것을 바탕으로 OnPacket(..)함수등을 만들어 패킷 처리를 하고 그랬었습니다.

CHandler 클래스를 상속받고, 가상함수등을 이용하고 Reactor에 등록시에도 그렇게 하여야 겠으나 그냥 어찌어찌 만들어진 코드입니다. 핑계를 데면 급히 만든 코드이니......... 또 관리자가 STL을 모른다른 이유로 또 C라는 한정적인 이유로 그냥 배열로 CHandler들을 관리하게 될 허접 SOCKETBOX를 만들었습니다.

그리 잘 따른 코드는 아니나 프레임웍이라 생각하고 보신다면 비지니스로직과 네트워크단의 분류가 확실히 되었음을 아실겁니다.

비지니스로직단에서는 마치 쓰레드를 사용하는것 마냥 착각하게 됩니다.

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
	SOCKETBOX	*socketBox;
	DISPATCHER	*dispatcher;
	void		*mainArg;
} REACTOR;

typedef struct
{
	REACTOR		*reactor;
	TCPCLIENT	*tcpClient;
	TIMESPEC	 timeout;
	TIMESPEC	 lastAccessTime;
} CHANDLER;


//유저가 작성해야 하는 함수==================================================
//연결되었을때 호출
int  CHandler_Open(CHANDLER *cHandler, TCPCLIENT *tcpClient, void *mainArg);
//데이터가 들어왔을때 호출
int  CHandler_Input(CHANDLER *cHandler, TCPCLIENT *tcpClient);
//연결이 끊겼을때 호출
void CHandler_Close(CHANDLER *cHandler, TCPCLIENT *tcpClient);
//예약한 시간설정이 되었을때 호출
int  CHandler_TimeOut(CHANDLER *cHandler, TCPCLIENT *tcpClient);

//  REACTOR 생성시 호출될 함수
void  Reactor_Open(REACTOR *Reactor);
//  REACTOR 타임아웃시 호출될 함수
void  Reactor_TimeOut(REACTOR *Reactor);
//  REACTOR 파괴시 또는 종료시 호출될 함수
void  Reactor_Close(REACTOR *Reactor);
//===========================================================================


//  REACTOR 생성자
REACTOR  *Reactor_Create(REACTOR *mainArg);
//  REACTOR 파괴자
void  Reactor_Destroy(REACTOR *Reactor);
//  REACTOR 실행
void  Reactor_Run(REACTOR *Reactor);

//유저가 사용할 수 있는 함수=================================================
//새로운 tcpClient를 등록
int   Reactor_Add(REACTOR *Reactor, TCPCLIENT *tcpClient);
//tcpClient를 삭제
int   Reactor_Del(REACTOR *Reactor, TCPCLIENT *tcpClient);

//타임아웃 설정
void  CHandler_SetTimeOut(CHANDLER *cHandler const int sec);

//fd값을 돌려줌
int   CHandler_Getfd(CHANDLER *cHandler);

//최근 접근 시간 셋팅함.
int   CHandler_SetAccessTime(CHANDLER *cHandler);

//최근 접근 시간 셋팅후 지난 시간을 밀리세컨드로 반환
long  CHandler_GetPastTime(CHANDLER *cHandler);

//자신의 아규먼트를 저장
int   CHandler_SetUserArg(CHANDLER *cHandler void *userArg);

//해당 핸들러에 저장한 아규먼트를 가져옮
void *CHandler_GetUserArg(CHANDLER *cHandler);

//생성시 저장했던 아규먼트를 가져옮
int   CHandler_GetMainArg(CHandler *cHandler);

//TCPCLIENT객체를 가져옮
TCPCLIENT *CHandler_GetTcpClient(CHandler *cHandler);

#ifdef __cplusplus
}
#endif

편집과정에서 몇가지 빠진함수가 있기도 하네요.

위와같이 작성하고 CHandler에서 사용할 변수도 CHandler_SetUserArg로 구조체를 통해 등록하여 사용했습니다. 따라서 전역변수를 일체 사용하지 않아도 되는 코드를 생성할 수 있었으며 연결당 개별관리를 Reactor가 CHandler이란것을 통해 해주었으며 CHandler_Open등에서 -1을 리턴하면 무조건 CHandler_Close를 호출하도록 하여 Close함수를 쓸 이유도 없게 되었구요.

특히나 편리했던 부분은 TimeOut부분을 Reactor에서 관리하고 이벤트처리하여 주므로 프로토콜 문서에 따라 복잡해질 로직이 아주 심하게 편해졌다고 말씀 드릴 수 있네요..TimeOut은 커넥트당 개별관리를 Reactor에서 해줍니다. 일반적으로 처리하는 방식인 일정 시간마다 전체 루프를 돌며 하는것이 아니기 때문에 좀 더 안정적이라고 할 수 있겠죠.

이것을 사용한 결과...다른사람이 사용함으로써 생기는 문제에 있어서 제가 그 사람의 비지니스 로직까지 알 필요 없이 이 부분에 대해서만 점검하거나 버그 수정정도에서 마무리 됩니다. 전 이에 관련된 문서나 알고리즘(?) 정도만 철저히 하면 제가 맡은 소켓 라이브러리 부분은 완료 되는 것이었죠.

다른 사람들은 커넥트되는것을 또 데이터가 들어오는것을, 타임아웃되는것을 직접 코드로 작성할 이유가 없었습니다. 그냥 이벤트가 들어오는 데로 처리하면 되는거니까요. 최소한의 지식은 커넥트와 센드, 서버로 띄우는것인데요. 이것들도 랩핑하여 라이브러리화 했습니다.

아마도 C만 하신 분들은 아주 심하게 생소하리라 추측됩니다. 이의가 있으신분은 언제든지요.....

실력자분들이 엄청 많을텐데...허접한 코드....마니 챙피하네요... :(

ㅡ,.ㅡ;;의 이미지

umean2me wrote:

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************
 DISPATCHER			: Dispatcher 식별자
 size_t size		: 현재 등록되어 있는 fd 수
 size_t maxfds		: 최대 등록 가능한 fd 수(필요에 따라 수시로 증가)
 pollFDs			: 현재 사용하고 있는 struct pollfd 구조체 포인터
******************************************************************************/
typedef struct
{
	size_t size;
	size_t maxfds;
	struct pollfd *pollFDs;
} DISPATCHER;

/******************************************************************************
 Dispatcher_Create(const size_t maxfds)
 Dispatcher_Create는 calloc를 통해 DISATCHER구조체를 생성하고 생성된 구조체를
 반환한다.
******************************************************************************/
DISPATCHER *Dispatcher_Create();


/******************************************************************************
 Dispatcher_Destroy(DISPATCHER *dispatch)
 Dispatcher_Create를 통해 생성된 구조체를 free를 통해 소멸시킨다.
******************************************************************************/
void Dispatcher_Destroy(DISPATCHER *dispatch);


/******************************************************************************
 Dispatcher_Add(DISPATCHER *dispatch)
 DISPATCHER의 식별자에 fd를 추가함으로써 poll이 fd를 감시할 수 있도록 한다.
******************************************************************************/
int Dispatcher_Add(DISPATCHER *dispatch, const int fd);


/******************************************************************************
 Dispatcher_Del(DISPATCHER *dispatch)
 DISPATCHER의 식별자에 fd를 삭제함으로써 poll이 fd를 감시에서 제거한다.
******************************************************************************/
int Dispatcher_Del(DISPATCHER *dispatch, const int fd);


/******************************************************************************
 Dispatcher_Wait(DISPATCHER *dispatch, const long timeout)
 등록된 fd들을 감시한다. 또 한 이 함수를 사용한 시점에서는 Block되며 이벤트
 가 발생할때까지 대기하게 된다. timeout으로 대기시간을 설정하게 되면 대기시
 간 이후에 함수를 빠져나가게 된다. 대기시간은 밀리세컨드이다.
******************************************************************************/
int Dispatcher_Wait(DISPATCHER *dispatch, const long timeout);


/******************************************************************************
 Dispatcher_CurfdsSize(DISPATCHER *dispatch) 
 DISPATCHER 에 현재까지 추가된 소켓의 수를 반환한다.
******************************************************************************/
size_t Dispatcher_CurfdsSize(DISPATCHER *dispatch);

#ifdef __cplusplus
}

poll을 객체형식으로 만들어 놓은겁니다. poll의 지저분한(?) 고유 코드는 다 빠지고 이것만으로 하니 별 신경쓸께 없었습니다. 위의 함수군을 사용하는 일은 다른 사람은 없었습니다. 이것은 밑의 Reactor을 만들기 위해 만들어 놓은 것이죠. 써도 별상관 없겠지만 이걸 익히려 노력은 안하리라 생각했기 때문입니다.

객체 형식으로 만들었다니.. 님소스를 다보진 않았지만.. 이게 왜.. 객체형식인지 모르겠습니다.
물론 말의 의미를 따져보다면 애초에 IT 분야에 객체라는 말자체 가 모호하지만말이죠..님이 구현한건 OOP 에서 말하는객체와는 약간다른의미인듯하군요..

또한 잘만들려는 생각이 있으면 Lib형태로 만들어 사용하는것은 당연하겠죠.. 당연히 lib내부를 까보는일은 없어야하구요..

한마디로 이것은 흔히말하는 구조화한것이라 볼수 있습니다.

Quote:

다음은 Reactor패턴을 C수준에서 응용한겁니다. 더 세밀히 하자면 함수포인터를 사용해야 했으나..그럴만한 시간적..ㅜㅜ..

Client Handler(CHandler)는 접속된 각각의 개별 커넥션을 말합니다. 그리고 이것들의 이벤트를 관리하며 처리하는 Reactor이 존재합니다. 사용자는 CHandler의 이벤트 발생시에 처리할 부분을 작성하게 됩니다. 즉 비지니스 로직이 들어갑니다.

Reactor은 TCPCLIENT 객체를 추가하게 되면 CHANDLER(Client Handler)를 생성하게 됩니다. 그리고 CHandler_*함수를 각 이벤트 분류에 따라 호출하게 해줍니다. '유저가 작성해야할 함수' 가 가상함수부분인데...여하튼 이 부분을 사용자가 작성해야 전체가 완성됩니다. 이 부분은 비지니스 로직이 들어가야할 부분이죠. 이것을 바탕으로 OnPacket(..)함수등을 만들어 패킷 처리를 하고 그랬었습니다.

CHandler 클래스를 상속받고, 가상함수등을 이용하고 Reactor에 등록시에도 그렇게 하여야 겠으나 그냥 어찌어찌 만들어진 코드입니다. 핑계를 데면 급히 만든 코드이니......... 또 관리자가 STL을 모른다른 이유로 또 C라는 한정적인 이유로 그냥 배열로 CHandler들을 관리하게 될 허접 SOCKETBOX를 만들었습니다.

그리 잘 따른 코드는 아니나 프레임웍이라 생각하고 보신다면 비지니스로직과 네트워크단의 분류가 확실히 되었음을 아실겁니다.

잘된구조화란것이 바로 비지니스로직과 Lib 부분이 잘분리된것입니다.

Quote:

비지니스로직단에서는 마치 쓰레드를 사용하는것 마냥 착각하게 됩니다.

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
	SOCKETBOX	*socketBox;
	DISPATCHER	*dispatcher;
	void		*mainArg;
} REACTOR;

typedef struct
{
	REACTOR		*reactor;
	TCPCLIENT	*tcpClient;
	TIMESPEC	 timeout;
	TIMESPEC	 lastAccessTime;
} CHANDLER;


//유저가 작성해야 하는 함수==================================================
//연결되었을때 호출
int  CHandler_Open(CHANDLER *cHandler, TCPCLIENT *tcpClient, void *mainArg);
//데이터가 들어왔을때 호출
int  CHandler_Input(CHANDLER *cHandler, TCPCLIENT *tcpClient);
//연결이 끊겼을때 호출
void CHandler_Close(CHANDLER *cHandler, TCPCLIENT *tcpClient);
//예약한 시간설정이 되었을때 호출
int  CHandler_TimeOut(CHANDLER *cHandler, TCPCLIENT *tcpClient);

//  REACTOR 생성시 호출될 함수
void  Reactor_Open(REACTOR *Reactor);
//  REACTOR 타임아웃시 호출될 함수
void  Reactor_TimeOut(REACTOR *Reactor);
//  REACTOR 파괴시 또는 종료시 호출될 함수
void  Reactor_Close(REACTOR *Reactor);
//===========================================================================


//  REACTOR 생성자
REACTOR  *Reactor_Create(REACTOR *mainArg);
//  REACTOR 파괴자
void  Reactor_Destroy(REACTOR *Reactor);
//  REACTOR 실행
void  Reactor_Run(REACTOR *Reactor);

//유저가 사용할 수 있는 함수=================================================
//새로운 tcpClient를 등록
int   Reactor_Add(REACTOR *Reactor, TCPCLIENT *tcpClient);
//tcpClient를 삭제
int   Reactor_Del(REACTOR *Reactor, TCPCLIENT *tcpClient);

//타임아웃 설정
void  CHandler_SetTimeOut(CHANDLER *cHandler const int sec);

//fd값을 돌려줌
int   CHandler_Getfd(CHANDLER *cHandler);

//최근 접근 시간 셋팅함.
int   CHandler_SetAccessTime(CHANDLER *cHandler);

//최근 접근 시간 셋팅후 지난 시간을 밀리세컨드로 반환
long  CHandler_GetPastTime(CHANDLER *cHandler);

//자신의 아규먼트를 저장
int   CHandler_SetUserArg(CHANDLER *cHandler void *userArg);

//해당 핸들러에 저장한 아규먼트를 가져옮
void *CHandler_GetUserArg(CHANDLER *cHandler);

//생성시 저장했던 아규먼트를 가져옮
int   CHandler_GetMainArg(CHandler *cHandler);

//TCPCLIENT객체를 가져옮
TCPCLIENT *CHandler_GetTcpClient(CHandler *cHandler);

#ifdef __cplusplus
}
#endif

편집과정에서 몇가지 빠진함수가 있기도 하네요.

위와같이 작성하고 CHandler에서 사용할 변수도 CHandler_SetUserArg로 구조체를 통해 등록하여 사용했습니다. 따라서 전역변수를 일체 사용하지 않아도 되는 코드를 생성할 수 있었으며 연결당 개별관리를 Reactor가 CHandler이란것을 통해 해주었으며 CHandler_Open등에서 -1을 리턴하면 무조건 CHandler_Close를 호출하도록 하여 Close함수를 쓸 이유도 없게 되었구요.

특히나 편리했던 부분은 TimeOut부분을 Reactor에서 관리하고 이벤트처리하여 주므로 프로토콜 문서에 따라 복잡해질 로직이 아주 심하게 편해졌다고 말씀 드릴 수 있네요..TimeOut은 커넥트당 개별관리를 Reactor에서 해줍니다. 일반적으로 처리하는 방식인 일정 시간마다 전체 루프를 돌며 하는것이 아니기 때문에 좀 더 안정적이라고 할 수 있겠죠.

이것을 사용한 결과...다른사람이 사용함으로써 생기는 문제에 있어서 제가 그 사람의 비지니스 로직까지 알 필요 없이 이 부분에 대해서만 점검하거나 버그 수정정도에서 마무리 됩니다. 전 이에 관련된 문서나 알고리즘(?) 정도만 철저히 하면 제가 맡은 소켓 라이브러리 부분은 완료 되는 것이었죠.

다른 사람들은 커넥트되는것을 또 데이터가 들어오는것을, 타임아웃되는것을 직접 코드로 작성할 이유가 없었습니다. 그냥 이벤트가 들어오는 데로 처리하면 되는거니까요. 최소한의 지식은 커넥트와 센드, 서버로 띄우는것인데요. 이것들도 랩핑하여 라이브러리화 했습니다.

아마도 C만 하신 분들은 아주 심하게 생소하리라 추측됩니다. 이의가 있으신분은 언제든지요.....

실력자분들이 엄청 많을텐데...허접한 코드....마니 챙피하네요... :(

전역을 사용하지 않았다고 객체지향이되것이 아니란건 아실텐데요...
원래 프로그램할때 웬만하면 전역은 사용하지 않죠..

아무리봐도 님프로그램은 구조화를 한것이군요..

물론 저는 구조화가 객체지향보다 뒤지거나 크게 다른의미라고 생각하지도 않습니다만...


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

sangwoo의 이미지

doldori wrote:
김지훈 wrote:
그런의미에서 저는 계산프로그램을 짤때 포트란,C를 두고
왜 C++로 짜느냐 하는게 참 궁금합니다.

편하니까요. :-) 예를 들어 C로 행렬 연산 프로그램을 만들 때 거의 똑같은 코드인데도
float와 double용을 따로 만들다 보면 이게 무슨 짓인가 하는 생각이 들지요.
(포트란도 사정은 비슷할 듯 합니다.) 이런 경우 C++의 템플릿을 쓰면 정말 편하죠.
템플릿을 쓴다고 성능이 저하되는 것도 아니고요.
연산자 오버로딩도 코딩의 편의성이나 가독성을 크게 증진시킬 수 있습니다.

김지훈 wrote:
구체적인 예(성공적인 사례나 계산프로그램인데도 OOP로 짤 수밖에 없는경우)
를 알고 싶어요 :)

oonumerics.org
이 중의 많은 라이브러리가 템플릿을 쓰고 있군요.

템플릿을 사용하면 함수 호출 오버헤드가 줄어드니까 오히려 C++가 C보다 빠른 경우도 많은 것으로 알고 있습니다. :-)
저는 회사에 있을 때까지는 계속 C로만 일을 하다가, C++를 얼마전부터 공부하기 시작했는데 (현재는 계산하는 랩에서 공부합니다.) 정말 큰 언어라는 게 느껴져서 겁이 납니다 ㅠㅜ

----
Let's shut up and code.

umean2me의 이미지

ㅡ,.ㅡ;; wrote:

잘된구조화란것이 바로 비지니스로직과 Lib 부분이 잘분리된것입니다.

프레임웍이란걸 놓치셨군요. 저것의 핵심은 프레임웍입니다. 뭐 아주 짜~~근 프레임웍이지만서도요. 프레임웍이 무엇인지 말씀해 주셨으면 좋겠습니다. 게다가 C에서는 말씀하신 그것의 분리가 절대적이지 않을 수 있으나 OOP적 개념에서는 절대적으로 필요한 행위라고 생각되는 군요.

ㅡ,.ㅡ;; wrote:

전역을 사용하지 않았다고 객체지향이되것이 아니란건 아실텐데요...
원래 프로그램할때 웬만하면 전역은 사용하지 않죠..

아무리봐도 님프로그램은 구조화를 한것이군요..

물론 저는 구조화가 객체지향보다 뒤지거나 크게 다른의미라고 생각하지도 않습니다만...

트집을 잡으시려거든 남의 글을 꼼꼼히 읽거나 아니면 제데로 아셨으면 하는 바램이네요.

전부터 한마디를 가지고 마치 상대방 주장의 요지인듯 쓰는 오류는 정말 안하셨으면 좋겠습니다. 기분이 좋지 않네요.

제가 전역을 쓰지않는 것이 진정한 객체지향이라고 했던가요? 그럼 싱글턴은 모라 부릅니까..그리고 웬만하면이 아니라 아이에 없게 짜도록 노력합니다.

님께서는 아직 객체지향을 잘 이해 못하시는것 같습니다. 또는 제 추측입니다만 님께서는 객체지향적 프로그래밍의 경험이 거의 없거나 적은것으로 생각됩니다.

이것은 언어가 아니라 개념이라고 생각합니다.

제가 잘났다고 말씀드리는것이 아니라 ACE 프레임웍(책 : C++ 네트워크프로그래밍 1,2 / ACE 프로그래머 가이드 참조)에서 REACTOR 패턴이란것을 간단하게 옮겨온 구조입니다. 물론 추상화라던가 이런 시간적으로도 실력으로도 더군다나 C로 그렇게 투자하고 싶지도 않습니다. 더구나 그리 뛰어난 설계능력을 가지진 못했으니...저런것을 배껴 오는 수 밖에 없는 것이죠. C++이었다면 ACE를 사용했을 겁니다.

제가 아는 객체지향적이란 책임과 역할의 분담입니다.(뭐 찾아보시면 훨 많은 것들이 나올테니..)

위에서 Dispatcher이란 놈은 네트워크프로그래밍에서 흔히들 작성해서 쓰는 일반적인 클래스를 C로 바꾼것입니다. 함수 수준의 작업이 아닌 또다른 핵심적 프로세스로 역할을 하게 됩니다. 바로 올바르게 디스패칭해야만 하는 역할과 책임을 가집니다. 디스패칭해서 받은 객체를 Reactor에서는 또다른 SOCKETBOX라는 객체에게 줍니다.

그러면 SOCKETBOX객체는 알맞은 CHandler객체를 호출합니다. Reactor에서 Dispatcher가 가지고 있는 구조체에 대해서는 별 관심이 없죠. 또한 SOCKETBOX가 가지는 구조체에 대해서도 관심이 없습니다. 더군다나 어떻게 처리를 하는가에 대해서도 전혀 관심을 가질 필요가 없습니다.각각의 객체에게 맞긴 행위에 대해서 올바르게만 처리를 바랄뿐입니다. 또다른 프로세스의 수준이죠. (책-OBJECT 디자인 참조, 다양한 결합방법에 대해 설명해주고 디자인 방법을 알려주고 있습니다.)

허나 일반적으로 우리가 만드는 구조적인 프로그래밍에서는 구조체를 통해서 작업(프로세스)수준이 아니라 함수수준에서의 결과물을 다시 메인시퀸서로 끌고 오죠. 즉 메인에서는 구조체안의 데이터에 간섭도 해야하고 별도의 함수를 통해서 그 결과물을 가져와야만 합니다. 그리고 이런 명령들을 통해서 구조체의 내용을 조정하게 됩니다.

메인에서는 객체지향적보다 역할과 책임이 크게 되고 함수의 한시적 사용이 있을 수 있으며 각 함수의 책임과 역할이 작아 버그 수정시에는 모든 프로세싱 과정을 봐야합니다. 객체지향적인 부분에서는 해당 객체에 대해서만 관심을 갖습니다.

제가 작성한 DISPATCHER는 개념적으로 멤버함수들을 가지고 있습니다. 그리고 DISPATCHER구조체는 얼마든지 은닉이 가능한 부분입니다.(해당업체에서 필요이상의 행위는 하지 않았습니다.) 또한 DISPATCHER의 구조체를 다를 줄 아는 함수들은 개념적으로 만들어진 멤버함수들 뿐입니다. 그걸 갑자기 밖으로 끄집어 내서 Reactor에서 주무른다면 어떻게 된다고 생각하십니까? 구조화프로그래밍이라면 충분히 그러고도 남을 상황입니다. 내지는 멤버함수 개념이 없으니 그냥 구조체를 건드리고도 남을 상황인거죠.

님께서 이런 부분에 토론을 원하신다면 진정으로 OOP던 C++이던 자바던 책을 깊이 보신다거나 사용하신다거나 써보시고서 글을 올려주시기 바랍니다. 부탁드립니다.

님의 주장데로라면....남들은 구조적프로그맹과 별차이 없는것을 가지고 20여년 동안 연구하며 개발한다는 말이군요.

doldori의 이미지

sangwoo wrote:
저는 회사에 있을 때까지는 계속 C로만 일을 하다가, C++를 얼마전부터 공부하기 시작했는데 (현재는 계산하는 랩에서 공부합니다.) 정말 큰 언어라는 게 느껴져서 겁이 납니다 ㅠㅜ

저는 반대로 C를 쓰기가 겁나요.
C가 주는 자유로움이 이제는 부담스러워요.
늙었다는 증거인가... T.T
IsExist의 이미지

c든 c++ 이든 충분히 읽기 쉽게 짜는게 좋은거 같습니다.

개념도 중요하지만 그런 개념의 등장이 개념을 위한 개념이 아닌
읽기 쉽고 관리가 용이한 방향으로 발전해야 합니다.

저의 경우는 c언어에 너무 익숙한 나머지 자료중심의 c++ 코드를 작성하는 경향이
강합니다. 언능 고쳐야 하는데.

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

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

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

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

ㅡ,.ㅡ;;의 이미지

umean2me wrote:
ㅡ,.ㅡ;; wrote:

잘된구조화란것이 바로 비지니스로직과 Lib 부분이 잘분리된것입니다.

프레임웍이란걸 놓치셨군요. 저것의 핵심은 프레임웍입니다. 뭐 아주 짜~~근 프레임웍이지만서도요. 프레임웍이 무엇인지 말씀해 주셨으면 좋겠습니다. 게다가 C에서는 말씀하신 그것의 분리가 절대적이지 않을 수 있으나 OOP적 개념에서는 절대적으로 필요한 행위라고 생각되는 군요.


놓치긴요..좀더 가깝다고 주장할수 있으나
그렇다고 별반차이는 없습니다.
대부분 프레임웍구조로 만드는거 아닌가요?
그리고 특별히 더프레임웍이다라고 할만한것도 아닌듯하구요..

Quote:

ㅡ,.ㅡ;; wrote:

전역을 사용하지 않았다고 객체지향이되것이 아니란건 아실텐데요...
원래 프로그램할때 웬만하면 전역은 사용하지 않죠..

아무리봐도 님프로그램은 구조화를 한것이군요..

물론 저는 구조화가 객체지향보다 뒤지거나 크게 다른의미라고 생각하지도 않습니다만...

트집을 잡으시려거든 남의 글을 꼼꼼히 읽거나 아니면 제데로 아셨으면 하는 바램이네요.

전부터 한마디를 가지고 마치 상대방 주장의 요지인듯 쓰는 오류는 정말 안하셨으면 좋겠습니다. 기분이 좋지 않네요.

제가 전역을 쓰지않는 것이 진정한 객체지향이라고 했던가요? 그럼 싱글턴은 모라 부릅니까..그리고 웬만하면이 아니라 아이에 없게 짜도록 노력합니다.

님께서는 아직 객체지향을 잘 이해 못하시는것 같습니다. 또는 제 추측입니다만 님께서는 객체지향적 프로그래밍의 경험이 거의 없거나 적은것으로 생각됩니다.

이것은 언어가 아니라 개념이라고 생각합니다.


OOP가 언어가 아니라 개념이란건 여기 있는사람중에 모르는사람 없을듯합니다.
제가 트집잡으려고 생각하신다면 님이 곡해하시는겁니다.
제가 님트집잡을이유가 뭐가 있나요.. 느낀데로 솔직히 말씀드렸던겁니다.
상대방의 주장을 요지인듯이 쓴다면 오히려 잘된일아닌가요.. 거기서 잘못된것을 쉽게 지적할수 있으니까요..그러나님은이게 멉니까..
그러진못하고 용어가 뭔줄은아냐 찾아보라식으로 이건 상대를 일부러 기분나쁘게 만들겠다는 의사지요..
그렇지 않다면 오히려 님이 객체지향을 재데로 알고 있는지 의문입니다..

객체지향적인 언어에서 객체지향적이라고 주장하는 가장큰이유가 무엇이라고 생각하세요?
님은 이걸생각해보면 왜 제가 님이작성한것이 그런요소를 찾아볼수 없다고 했는지 아실겁니다.

Quote:

제가 잘났다고 말씀드리는것이 아니라 ACE 프레임웍(책 : C++ 네트워크프로그래밍 1,2 / ACE 프로그래머 가이드 참조)에서 REACTOR 패턴이란것을 간단하게 옮겨온 구조입니다. 물론 추상화라던가 이런 시간적으로도 실력으로도 더군다나 C로 그렇게 투자하고 싶지도 않습니다. 더구나 그리 뛰어난 설계능력을 가지진 못했으니...저런것을 배껴 오는 수 밖에 없는 것이죠. C++이었다면 ACE를 사용했을 겁니다.

제가 아는 객체지향적이란 책임과 역할의 분담입니다.(뭐 찾아보시면 훨 많은 것들이 나올테니..)

위에서 Dispatcher이란 놈은 네트워크프로그래밍에서 흔히들 작성해서 쓰는 일반적인 클래스를 C로 바꾼것입니다. 함수 수준의 작업이 아닌 또다른 핵심적 프로세스로 역할을 하게 됩니다. 바로 올바르게 디스패칭해야만 하는 역할과 책임을 가집니다. 디스패칭해서 받은 객체를 Reactor에서는 또다른 SOCKETBOX라는 객체에게 줍니다.

그러면 SOCKETBOX객체는 알맞은 CHandler객체를 호출합니다. Reactor에서 Dispatcher가 가지고 있는 구조체에 대해서는 별 관심이 없죠. 또한 SOCKETBOX가 가지는 구조체에 대해서도 관심이 없습니다. 더군다나 어떻게 처리를 하는가에 대해서도 전혀 관심을 가질 필요가 없습니다.각각의 객체에게 맞긴 행위에 대해서 올바르게만 처리를 바랄뿐입니다. 또다른 프로세스의 수준이죠. (책-OBJECT 디자인 참조, 다양한 결합방법에 대해 설명해주고 디자인 방법을 알려주고 있습니다.)

허나 일반적으로 우리가 만드는 구조적인 프로그래밍에서는 구조체를 통해서 작업(프로세스)수준이 아니라 함수수준에서의 결과물을 다시 메인시퀸서로 끌고 오죠. 즉 메인에서는 구조체안의 데이터에 간섭도 해야하고 별도의 함수를 통해서 그 결과물을 가져와야만 합니다. 그리고 이런 명령들을 통해서 구조체의 내용을 조정하게 됩니다.

메인에서는 객체지향적보다 역할과 책임이 크게 되고 함수의 한시적 사용이 있을 수 있으며 각 함수의 책임과 역할이 작아 버그 수정시에는 모든 프로세싱 과정을 봐야합니다. 객체지향적인 부분에서는 해당 객체에 대해서만 관심을 갖습니다.

제가 작성한 DISPATCHER는 개념적으로 멤버함수들을 가지고 있습니다. 그리고 DISPATCHER구조체는 얼마든지 은닉이 가능한 부분입니다.(해당업체에서 필요이상의 행위는 하지 않았습니다.) 또한 DISPATCHER의 구조체를 다를 줄 아는 함수들은 개념적으로 만들어진 멤버함수들 뿐입니다. 그걸 갑자기 밖으로 끄집어 내서 Reactor에서 주무른다면 어떻게 된다고 생각하십니까? 구조화프로그래밍이라면 충분히 그러고도 남을 상황입니다. 내지는 멤버함수 개념이 없으니 그냥 구조체를 건드리고도 남을 상황인거죠.

님께서 이런 부분에 토론을 원하신다면 진정으로 OOP던 C++이던 자바던 책을 깊이 보신다거나 사용하신다거나 써보시고서 글을 올려주시기 바랍니다. 부탁드립니다.

님의 주장데로라면....남들은 구조적프로그맹과 별차이 없는것을 가지고 20여년 동안 연구하며 개발한다는 말이군요.


C++로 구현한객체를 C로도 별반차이 없게 만들어질수 있죠..


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

corba의 이미지

umean2me wrote:
제가 작성한 DISPATCHER는 개념적으로 멤버함수들을 가지고 있습니다. 그리고 DISPATCHER구조체는 얼마든지 은닉이 가능한 부분입니다.(해당업체에서 필요이상의 행위는 하지 않았습니다.) 또한 DISPATCHER의 구조체를 다를 줄 아는 함수들은 개념적으로 만들어진 멤버함수들 뿐입니다. 그걸 갑자기 밖으로 끄집어 내서 Reactor에서 주무른다면 어떻게 된다고 생각하십니까? 구조화프로그래밍이라면 충분히 그러고도 남을 상황입니다. 내지는 멤버함수 개념이 없으니 그냥 구조체를 건드리고도 남을 상황인거죠.

FILE의 예를 드셨지만 OOP가 아니라도 옛날 부터 쓰고 있는 방식이니 OOP에서 좀더 직관적이고 편하게 할 수 있다고 해서 OOP의 전유물은 아니라고 봅니다.
또, C프로그래머 입장에서는 상당히 자연스러운 거겠지요. 보여주신 코드만으로는 C프로그래머들에게도 상당히 자연스럽습니다.
같은 결과물도 충분히 다른 과정으로 도출 될 수 있다는 생각을 하시면 편하실 것 같네요... :)
alwaysN00b의 이미지

ㅡ,.ㅡ;; wrote:

궂이 구조체를 선언하고 그내부에 함수포인터로 메모리할당함수를 정의하고 또 그멤버포인터편수에 다시 구조체를 연결하고 그구조체에 메모리를할당하게한다면...
좀어색하다는거죠..
문제는 오히려 성능저하를 시키는데도 말이죠..
제가 말하는건 이런것이었습니다. 오히려 성능저하에 보기도 힘들고 코딩양도 많아지는것을 고집스럽게 그렇게 하는건....안좋다고 봅니다.

C에서 구조체를 만들고 굳이 함수포인터로 메모리를 할당하는건 C에는 구조체를 선언할때 자동으로 메모리를 할당하고 초기화하는 기능이 없기 때문입니다.

객체의 개념을 알고 계신줄 알았는데요.

C++이나 JAVA나 나오기 이전에 OOP 구현을 어떻게 했을까요?

객체가 어떻게 생겼든 사용하는 사람은 인터페이스만 알고 있으면 다른 세세한 부분은 신경쓰지 않고 객체를 사용할수 있습니다.

도대체 말씀하신 부분에 뭐가 어색하고 어디가 성능저하를 일으킨다는 말씀이 신지요?
제가 걸어 링크걸어놓은 쓰레드는 읽어보셨는지요?

처음에 '절대' 하지 말자고 하시던 부분에 문제가 있었습니다.
분명 오해의 소지가 있는 말입니다. 지금은 '고집스럽게' 라고 말씀하셨지만요.

C로 OOP를 구현하기 보다는 C++을 사용하는게 훨씬 코드 가독성도 올라가고 코딩속도도 빠를것입니다.

하지만 C로 '절대' OOP 같은건 구현하지 말라는건 납득이 안됩니다.

C이든 C++이든 도구입니다.
못을 박아야하는데 지금 돌밖에 없고 망치살 돈이 없으면 돌로 박아야하는것 아닌가요?

그럼, 그전에 돌로 못을 박는걸 연습해놨으면 더 쉬운것 아닌가요?
돌로 못을 박아본 사람만 망치가 편하다는걸 알것입니다.

마지막으로, 링크건 쓰레드에 충분한 내용이 있었습니다.

언제나 시작

alwaysN00b의 이미지

ㅡ,.ㅡ;; wrote:
umean2me wrote:

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************
 DISPATCHER			: Dispatcher 식별자
 size_t size		: 현재 등록되어 있는 fd 수
 size_t maxfds		: 최대 등록 가능한 fd 수(필요에 따라 수시로 증가)
 pollFDs			: 현재 사용하고 있는 struct pollfd 구조체 포인터
******************************************************************************/
typedef struct
{
	size_t size;
	size_t maxfds;
	struct pollfd *pollFDs;
} DISPATCHER;

/******************************************************************************
 Dispatcher_Create(const size_t maxfds)
 Dispatcher_Create는 calloc를 통해 DISATCHER구조체를 생성하고 생성된 구조체를
 반환한다.
******************************************************************************/
DISPATCHER *Dispatcher_Create();


/******************************************************************************
 Dispatcher_Destroy(DISPATCHER *dispatch)
 Dispatcher_Create를 통해 생성된 구조체를 free를 통해 소멸시킨다.
******************************************************************************/
void Dispatcher_Destroy(DISPATCHER *dispatch);


/******************************************************************************
 Dispatcher_Add(DISPATCHER *dispatch)
 DISPATCHER의 식별자에 fd를 추가함으로써 poll이 fd를 감시할 수 있도록 한다.
******************************************************************************/
int Dispatcher_Add(DISPATCHER *dispatch, const int fd);


/******************************************************************************
 Dispatcher_Del(DISPATCHER *dispatch)
 DISPATCHER의 식별자에 fd를 삭제함으로써 poll이 fd를 감시에서 제거한다.
******************************************************************************/
int Dispatcher_Del(DISPATCHER *dispatch, const int fd);


/******************************************************************************
 Dispatcher_Wait(DISPATCHER *dispatch, const long timeout)
 등록된 fd들을 감시한다. 또 한 이 함수를 사용한 시점에서는 Block되며 이벤트
 가 발생할때까지 대기하게 된다. timeout으로 대기시간을 설정하게 되면 대기시
 간 이후에 함수를 빠져나가게 된다. 대기시간은 밀리세컨드이다.
******************************************************************************/
int Dispatcher_Wait(DISPATCHER *dispatch, const long timeout);


/******************************************************************************
 Dispatcher_CurfdsSize(DISPATCHER *dispatch) 
 DISPATCHER 에 현재까지 추가된 소켓의 수를 반환한다.
******************************************************************************/
size_t Dispatcher_CurfdsSize(DISPATCHER *dispatch);

#ifdef __cplusplus
}

poll을 객체형식으로 만들어 놓은겁니다. poll의 지저분한(?) 고유 코드는 다 빠지고 이것만으로 하니 별 신경쓸께 없었습니다. 위의 함수군을 사용하는 일은 다른 사람은 없었습니다. 이것은 밑의 Reactor을 만들기 위해 만들어 놓은 것이죠. 써도 별상관 없겠지만 이걸 익히려 노력은 안하리라 생각했기 때문입니다.

객체 형식으로 만들었다니.. 님소스를 다보진 않았지만.. 이게 왜.. 객체형식인지 모르겠습니다.
물론 말의 의미를 따져보다면 애초에 IT 분야에 객체라는 말자체 가 모호하지만말이죠..님이 구현한건 OOP 에서 말하는객체와는 약간다른의미인듯하군요..

또한 잘만들려는 생각이 있으면 Lib형태로 만들어 사용하는것은 당연하겠죠.. 당연히 lib내부를 까보는일은 없어야하구요..

한마디로 이것은 흔히말하는 구조화한것이라 볼수 있습니다.

Quote:

다음은 Reactor패턴을 C수준에서 응용한겁니다. 더 세밀히 하자면 함수포인터를 사용해야 했으나..그럴만한 시간적..ㅜㅜ..

Client Handler(CHandler)는 접속된 각각의 개별 커넥션을 말합니다. 그리고 이것들의 이벤트를 관리하며 처리하는 Reactor이 존재합니다. 사용자는 CHandler의 이벤트 발생시에 처리할 부분을 작성하게 됩니다. 즉 비지니스 로직이 들어갑니다.

Reactor은 TCPCLIENT 객체를 추가하게 되면 CHANDLER(Client Handler)를 생성하게 됩니다. 그리고 CHandler_*함수를 각 이벤트 분류에 따라 호출하게 해줍니다. '유저가 작성해야할 함수' 가 가상함수부분인데...여하튼 이 부분을 사용자가 작성해야 전체가 완성됩니다. 이 부분은 비지니스 로직이 들어가야할 부분이죠. 이것을 바탕으로 OnPacket(..)함수등을 만들어 패킷 처리를 하고 그랬었습니다.

CHandler 클래스를 상속받고, 가상함수등을 이용하고 Reactor에 등록시에도 그렇게 하여야 겠으나 그냥 어찌어찌 만들어진 코드입니다. 핑계를 데면 급히 만든 코드이니......... 또 관리자가 STL을 모른다른 이유로 또 C라는 한정적인 이유로 그냥 배열로 CHandler들을 관리하게 될 허접 SOCKETBOX를 만들었습니다.

그리 잘 따른 코드는 아니나 프레임웍이라 생각하고 보신다면 비지니스로직과 네트워크단의 분류가 확실히 되었음을 아실겁니다.

잘된구조화란것이 바로 비지니스로직과 Lib 부분이 잘분리된것입니다.

Quote:

비지니스로직단에서는 마치 쓰레드를 사용하는것 마냥 착각하게 됩니다.

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
	SOCKETBOX	*socketBox;
	DISPATCHER	*dispatcher;
	void		*mainArg;
} REACTOR;

typedef struct
{
	REACTOR		*reactor;
	TCPCLIENT	*tcpClient;
	TIMESPEC	 timeout;
	TIMESPEC	 lastAccessTime;
} CHANDLER;


//유저가 작성해야 하는 함수==================================================
//연결되었을때 호출
int  CHandler_Open(CHANDLER *cHandler, TCPCLIENT *tcpClient, void *mainArg);
//데이터가 들어왔을때 호출
int  CHandler_Input(CHANDLER *cHandler, TCPCLIENT *tcpClient);
//연결이 끊겼을때 호출
void CHandler_Close(CHANDLER *cHandler, TCPCLIENT *tcpClient);
//예약한 시간설정이 되었을때 호출
int  CHandler_TimeOut(CHANDLER *cHandler, TCPCLIENT *tcpClient);

//  REACTOR 생성시 호출될 함수
void  Reactor_Open(REACTOR *Reactor);
//  REACTOR 타임아웃시 호출될 함수
void  Reactor_TimeOut(REACTOR *Reactor);
//  REACTOR 파괴시 또는 종료시 호출될 함수
void  Reactor_Close(REACTOR *Reactor);
//===========================================================================


//  REACTOR 생성자
REACTOR  *Reactor_Create(REACTOR *mainArg);
//  REACTOR 파괴자
void  Reactor_Destroy(REACTOR *Reactor);
//  REACTOR 실행
void  Reactor_Run(REACTOR *Reactor);

//유저가 사용할 수 있는 함수=================================================
//새로운 tcpClient를 등록
int   Reactor_Add(REACTOR *Reactor, TCPCLIENT *tcpClient);
//tcpClient를 삭제
int   Reactor_Del(REACTOR *Reactor, TCPCLIENT *tcpClient);

//타임아웃 설정
void  CHandler_SetTimeOut(CHANDLER *cHandler const int sec);

//fd값을 돌려줌
int   CHandler_Getfd(CHANDLER *cHandler);

//최근 접근 시간 셋팅함.
int   CHandler_SetAccessTime(CHANDLER *cHandler);

//최근 접근 시간 셋팅후 지난 시간을 밀리세컨드로 반환
long  CHandler_GetPastTime(CHANDLER *cHandler);

//자신의 아규먼트를 저장
int   CHandler_SetUserArg(CHANDLER *cHandler void *userArg);

//해당 핸들러에 저장한 아규먼트를 가져옮
void *CHandler_GetUserArg(CHANDLER *cHandler);

//생성시 저장했던 아규먼트를 가져옮
int   CHandler_GetMainArg(CHandler *cHandler);

//TCPCLIENT객체를 가져옮
TCPCLIENT *CHandler_GetTcpClient(CHandler *cHandler);

#ifdef __cplusplus
}
#endif

편집과정에서 몇가지 빠진함수가 있기도 하네요.

위와같이 작성하고 CHandler에서 사용할 변수도 CHandler_SetUserArg로 구조체를 통해 등록하여 사용했습니다. 따라서 전역변수를 일체 사용하지 않아도 되는 코드를 생성할 수 있었으며 연결당 개별관리를 Reactor가 CHandler이란것을 통해 해주었으며 CHandler_Open등에서 -1을 리턴하면 무조건 CHandler_Close를 호출하도록 하여 Close함수를 쓸 이유도 없게 되었구요.

특히나 편리했던 부분은 TimeOut부분을 Reactor에서 관리하고 이벤트처리하여 주므로 프로토콜 문서에 따라 복잡해질 로직이 아주 심하게 편해졌다고 말씀 드릴 수 있네요..TimeOut은 커넥트당 개별관리를 Reactor에서 해줍니다. 일반적으로 처리하는 방식인 일정 시간마다 전체 루프를 돌며 하는것이 아니기 때문에 좀 더 안정적이라고 할 수 있겠죠.

이것을 사용한 결과...다른사람이 사용함으로써 생기는 문제에 있어서 제가 그 사람의 비지니스 로직까지 알 필요 없이 이 부분에 대해서만 점검하거나 버그 수정정도에서 마무리 됩니다. 전 이에 관련된 문서나 알고리즘(?) 정도만 철저히 하면 제가 맡은 소켓 라이브러리 부분은 완료 되는 것이었죠.

다른 사람들은 커넥트되는것을 또 데이터가 들어오는것을, 타임아웃되는것을 직접 코드로 작성할 이유가 없었습니다. 그냥 이벤트가 들어오는 데로 처리하면 되는거니까요. 최소한의 지식은 커넥트와 센드, 서버로 띄우는것인데요. 이것들도 랩핑하여 라이브러리화 했습니다.

아마도 C만 하신 분들은 아주 심하게 생소하리라 추측됩니다. 이의가 있으신분은 언제든지요.....

실력자분들이 엄청 많을텐데...허접한 코드....마니 챙피하네요... :(

전역을 사용하지 않았다고 객체지향이되것이 아니란건 아실텐데요...
원래 프로그램할때 웬만하면 전역은 사용하지 않죠..

아무리봐도 님프로그램은 구조화를 한것이군요..

물론 저는 구조화가 객체지향보다 뒤지거나 크게 다른의미라고 생각하지도 않습니다만...

좀 심하게 딴지 하나 걸겠습니다.

코드도 다 안봤다고 말씀하시고 '아무리봐도 님프로그램은 구조화를 한것이군요..' 라고 하신건 힘들게 글올리신 분을 농락하는것 같습니다.

언제나 시작

ㅡ,.ㅡ;;의 이미지

alwaysN00b wrote:
ㅡ,.ㅡ;; wrote:

궂이 구조체를 선언하고 그내부에 함수포인터로 메모리할당함수를 정의하고 또 그멤버포인터편수에 다시 구조체를 연결하고 그구조체에 메모리를할당하게한다면...
좀어색하다는거죠..
문제는 오히려 성능저하를 시키는데도 말이죠..
제가 말하는건 이런것이었습니다. 오히려 성능저하에 보기도 힘들고 코딩양도 많아지는것을 고집스럽게 그렇게 하는건....안좋다고 봅니다.

C에서 구조체를 만들고 굳이 함수포인터로 메모리를 할당하는건 C에는 구조체를 선언할때 자동으로 메모리를 할당하고 초기화하는 기능이 없기 때문입니다.

객체의 개념을 알고 계신줄 알았는데요.

C++이나 JAVA나 나오기 이전에 OOP 구현을 어떻게 했을까요?

객체가 어떻게 생겼든 사용하는 사람은 인터페이스만 알고 있으면 다른 세세한 부분은 신경쓰지 않고 객체를 사용할수 있습니다.

도대체 말씀하신 부분에 뭐가 어색하고 어디가 성능저하를 일으킨다는 말씀이 신지요?
제가 걸어 링크걸어놓은 쓰레드는 읽어보셨는지요?

처음에 '절대' 하지 말자고 하시던 부분에 문제가 있었습니다.
분명 오해의 소지가 있는 말입니다. 지금은 '고집스럽게' 라고 말씀하셨지만요.

C로 OOP를 구현하기 보다는 C++을 사용하는게 훨씬 코드 가독성도 올라가고 코딩속도도 빠를것입니다.

하지만 C로 '절대' OOP 같은건 구현하지 말라는건 납득이 안됩니다.

C이든 C++이든 도구입니다.
못을 박아야하는데 지금 돌밖에 없고 망치살 돈이 없으면 돌로 박아야하는것 아닌가요?

그럼, 그전에 돌로 못을 박는걸 연습해놨으면 더 쉬운것 아닌가요?
돌로 못을 박아본 사람만 망치가 편하다는걸 알것입니다.

마지막으로, 링크건 쓰레드에 충분한 내용이 있었습니다.

님이 객체를 모르시나봅니다. 아니면 제글다시 읽어보세요..
그리고 어이없네요.. 누가 C로 OOP구현하지 말라고하던가요?
글을제대로 안읽오보시나보군요..
전체적으로 좀 엉뚱한글을 쓰셨군요..


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

alwaysN00b의 이미지

ㅡ,.ㅡ;; wrote:
님이 객체를 모르시나봅니다. 아니면 제글다시 읽어보세요..
그리고 어이없네요.. 누가 C로 OOP구현하지 말라고하던가요?
글을제대로 안읽오보시나보군요..
전체적으로 좀 엉뚱한글을 쓰셨군요..

ㅡ,.ㅡ;; wrote:
딴지일지 모릅니다만..
머하러 어렵게 C로 C++ 흉내냅니까... 그냥 C++ 사용하면되지..
C++ 흉내냈다고 해봤자 C++ 같지도 않구요..
C로는 그냥 C 처럼 짜는것이 가장 자연스럽습니다.

누가 그런코드로 짜놓은 소스가 있는데요..
보면 소스다지우고 싶습니다..^^;
메모리 오류도 많을뿐만아니라 메모리 할당해제도 재대로 안되있거든요..함수재사용은 매우안되고 있고..
문제는 오류를 잡아내기 무척힘듭니다.또한속도 무지 늦고..
시스템 리소스 엄청많이먹네요..

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

죄송합니다. 전 '이런건 절대 하지맙시다' 라고 하신게 뭘 뜻하는지 몰랐군요. 지금도 모르겠구요.

쓰레드가 C로 C++흉내내기 라고 하지만 C++흉내를 낸다는건 OOP를 구현한다고 봐도 될것이라 생각합니다.

쓰레드가 별로 발전적이지 못해지는것 같아 마지막으로 적고 가겠습니다.

언제나 시작

ㅡ,.ㅡ;;의 이미지

alwaysN00b wrote:

ㅡ,.ㅡ;; wrote:

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

죄송합니다. 전 '이런건 절대 하지맙시다' 라고 하신게 뭘 뜻하는지 몰랐군요. 지금도 모르겠구요.


"까봐야하는실정"을 절대 하지맙시다라고 했죠..
OOP하지말라는소리가아니라 C++흉내내기에그쳐버려서 OOP의 장점은없고 오히려 그내부까지 다들추어보아야하는 이렇게 는하지말자는거죠
그적용이 될만한곳에 써서 장점을 살리게 할수있는곳에는 그렇게 하는게 좋구요. 제말은 C++흉내만 냈다고 무조건 OOP가되며 좋아지는건 아니란겁니다.


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

irondog의 이미지

짧은 시간 동안 C++고수들이 많이 생겼나 보네요. C++이 쓰기 쉽다고 하시는 분들이 많으니시... 제 경험엔 참 어렵고 번잡한 언어구나 생각하고 있었는데... C++문법 공부하다 보면 오히려 OOP하기 힘들겠다고 까지 주장하곤 했었죠.

최근에 스탠다드한 라이브러리도 만들어졌다고 해서 서버 코딩에 다시 써볼까 했는데 아직은 적응이 잘 안되네요. 다음 프로젝트에서나 다시 시도해보기로 하고 일단 포기.

OOP라하면... 추상화, 다형성, 상속 요게 핵심인 것 같은데...
요거 프로그래밍 하면서 잘 적용하고 계시나요? 전 임베디드에서 윈도같은 GUI라이브러리 만들때 이 3가지 개념이 참으로 유용하겠다고 생각 했는데 그 외에는 쓸모를 잘 모르겠더라구요.

잘 만들어진 클래스를 쓰더라도 상속 받아서 기능을 확장하려면 해당 소스를 정확히 분석하지 않고는 무서워서 확장하기 힘들죠. 메모리 관리가 막 꼬이면서 알 수 없는 오류를 마구 만들게 되거든요. 상속이라는게 코드의 흐름에 끼어들 수 밖에 없는데 소스를 다 보기 전에는 오류 만들기 아주 쉽죠.

게다가 속을 감추고 상속을 통해 확장성을 제공하려면 클래스 개발자가 얼마나 고민을 많이 해야 하는지... 이용자가 해서는 안될 목록 만들다가 영혼에 기쓰날 수도 있습니다. -.-;

OOP캡슐화 하지 말자고 하신 말씀의 뜻은 그런뜻이 아닌가 싶어요. 템플릿 정도라면 모를까 상속을 통해 코드의 재사용성을 높인다는 말도 그래서 말이 안된다고 생각하고 있었습니다. 차라리 코드의 재사용성을 높이려면 오픈소스로 가는게 맞는 거라고 봅니다. :D

doldori의 이미지

irondog wrote:
잘 만들어진 클래스를 쓰더라도 상속 받아서 기능을 확장하려면 해당 소스를 정확히 분석하지 않고는 무서워서 확장하기 힘들죠. 메모리 관리가 막 꼬이면서 알 수 없는 오류를 마구 만들게 되거든요. 상속이라는게 코드의 흐름에 끼어들 수 밖에 없는데 소스를 다 보기 전에는 오류 만들기 아주 쉽죠.

글쎄요... 상속받기 위해서는 소스 코드가 아니라 부모 클래스의 문서를 봐야 하지
않습니까? 그 문서에서는 클래스의 사용법이 당연히 나와 있겠고요. 소스 코드를
봐야 하는 상황 자체가 비정상적이라고 봅니다.

irondog wrote:
템플릿 정도라면 모를까 상속을 통해 코드의 재사용성을 높인다는 말도 그래서 말이 안된다고 생각하고 있었습니다.

이 말을 들으면 Qt 개발자를 포함한 많은 사람들이 섭섭해 하겠군요. ;-)
irondog의 이미지

doldori wrote:
irondog wrote:
잘 만들어진 클래스를 쓰더라도 상속 받아서 기능을 확장하려면 해당 소스를 정확히 분석하지 않고는 무서워서 확장하기 힘들죠. 메모리 관리가 막 꼬이면서 알 수 없는 오류를 마구 만들게 되거든요. 상속이라는게 코드의 흐름에 끼어들 수 밖에 없는데 소스를 다 보기 전에는 오류 만들기 아주 쉽죠.

글쎄요... 상속받기 위해서는 소스 코드가 아니라 부모 클래스의 문서를 봐야 하지
않습니까? 그 문서에서는 클래스의 사용법이 당연히 나와 있겠고요. 소스 코드를
봐야 하는 상황 자체가 비정상적이라고 봅니다.
irondog wrote:
템플릿 정도라면 모를까 상속을 통해 코드의 재사용성을 높인다는 말도 그래서 말이 안된다고 생각하고 있었습니다.

이 말을 들으면 Qt 개발자를 포함한 많은 사람들이 섭섭해 하겠군요. ;-)

윈도같은 GUI라이브러리에는 적합하다고 했으니 섭섭해 하진 않을꺼에요. :o

배추의 이미지

doldori wrote:

이 말을 들으면 Qt 개발자를 포함한 많은 사람들이 섭섭해 하겠군요. ;-)

그놈개발자, novell, ibm, RMS, ESR, google은 아닐겁니다.

제아이디와비번은 배추, 12ws 입니다.

익명 사용자의 이미지

ㅡ,.ㅡ;; wrote:

OOP가 언어가 아니라 개념이란건 여기 있는사람중에 모르는사람 없을듯합니다.
제가 트집잡으려고 생각하신다면 님이 곡해하시는겁니다.
제가 님트집잡을이유가 뭐가 있나요.. 느낀데로 솔직히 말씀드렸던겁니다.
상대방의 주장을 요지인듯이 쓴다면 오히려 잘된일아닌가요.. 거기서 잘못된것을 쉽게 지적할수 있으니까요..그러나님은이게 멉니까..
그러진못하고 용어가 뭔줄은아냐 찾아보라식으로 이건 상대를 일부러 기분나쁘게 만들겠다는 의사지요..
그렇지 않다면 오히려 님이 객체지향을 재데로 알고 있는지 의문입니다..

'상대방의 주장을 요지인듯이 쓴다면 오히려 잘된일아닌가요'
는 제 글을 또 잘못 읽으셨군요. 솔직히 님의 글은 아주 많이 답답합니다. 말이란게 아다르고 어다르다는거 구분하셨으면 좋겠네요.

'전부터 한마디를 가지고 마치 상대방 주장의 요지인듯 쓰는 오류는 정말 안하셨으면 좋겠습니다'
라고 했는데요. 핵심은 한마디를 가지고 그 글의 주제인냥 또는 전체인냥 말씀 하신다는 겁니다. 근데 또 그렇게 말씀하시면 제가 어쩌라는 겁니까?? 님은 계속 그런 오류를 범하고 계시네요.

님께서 글을 파악하시는걸 보면 '아버지가방에 들어가셨다' 이거랑 별반 차이가 없다는 겁니다.

기분 나쁘셨다면 죄송합니다. 하지만 책을 보시라는 이유는 그걸 여기에 요약한다 한들 분량이 상당히 되더라입니다. 또한 제가 표현하는것보다 보다 확실히 알 수 있기 때문입니다.

Quote:

그리고 특별히 더프레임웍이다라고 할만한것도 아닌듯하구요

누누히 이야기 하지만...책을 참조하신다거나 해주셨으면 좋겠구요.
또 누누히 이야기하지만 제가 어떤 단어를 어디서 어떻게 사용했는지 차분히 보셨으면 좋겠습니다.

분명 저는 이전의 작업 결과물을 편집했다고 글에 적었고 또 C로 거창하게 작업하기는 더더욱 싫다는 표현으로 보여드린다고 말씀드린게 기억나는데요..마치 전체인냥 표현하시고 계십니다.

님께 유리한 부분만을 사용하여 왜곡시켜 저의 주장인냥 말씀하시니 말씀하시는 것이 적대감을 표현한다고 느껴집니다. 그게 아니라면 기분 나쁘셨던것에 대해 먼저 사과를 드리겠습니다. 님께서 고의적이 아니라면 글을 읽을때 주의깊게 읽기를 부탁드리겠습니다.

corba wrote:

FILE의 예를 드셨지만 OOP가 아니라도 옛날 부터 쓰고 있는 방식이니 OOP에서 좀더 직관적이고 편하게 할 수 있다고 해서 OOP의 전유물은 아니라고 봅니다.
또, C프로그래머 입장에서는 상당히 자연스러운 거겠지요. 보여주신 코드만으로는 C프로그래머들에게도 상당히 자연스럽습니다.
같은 결과물도 충분히 다른 과정으로 도출 될 수 있다는 생각을 하시면 편하실 것 같네요...

전 전유물이라 주장한적이 없는데...언어라기 보다 개념이라고는 했습니다. 여하튼 님의 말에 동감합니다만 예제에서 제가 뿌린 코드가 C프로그래머에게 상당히 자연스럽다면 고수님들이라 생각합니다. 대체적으로 C프로그래머들에게 상당히 자연스럽다는 것은 제 직장생활 결과에 따르자면 그렇지 못하다라고 생각하거든요.

저 때문에 더 게시판이 흐려지는듯 합니다. 여기서 그만 쓰겠습니다.

umean2me의 이미지

이런이런....위 두글은 제글인데....로그인한줄 알았는데 아니네요..ㅜㅜ....운영자님 위 두글중 윗글은 삭제가 안되는건가요?

죄송합니다.....ㅜㅜㅜ....

---
삭제했습니다 (관리자, pynoos)

ㅡ,.ㅡ;;의 이미지

umean2me wrote:
이런이런....위 두글은 제글인데.......

괜히 남의 코딩가지고 왈가왈부하는거 같아서 ...
그럴수록님이 기분나빠서 더 안좋은소리만나올것이기때문에 ..
길게 얘기는 안하겠습니다.
님코드가 머 생소하리라고 말씀하셨는데 만일그렇다면 님이 여테 특정스타일의 코드만 구경하셨나보네요..
구조나 그어떤것에도 새롭다혹은 생소하다할만한것은 전혀없구요..그냥 일반적입니다....
제말이 그짓말인가 여기 오시는분들한테 투표해봐도 좋을듯하군요..아마도 대부분 그냥 일반적인C라고하지 마치 C++같다라던가 새롭다는사람은 없을껄요..
사실 소스보니 여기 있는 암호화 통신모듈이 님이 보여주신거랑 매우비슷하게 생긴게 여기도 있군요....소스제것이 아니기때문에 보여드릴수는없습니다.

그리고 lib로 제공될것이라면 절대 내부를 까보는일은 없어야합니다. 아예그럴수 없기도 하구요..
그리고 책은 님이 좀더 보셔야할듯합니다.
보실때 C++을 왜 OOP 언어라고 하는지 보시고 다시한번 생각해보세요..


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

umean2me의 이미지

글을 손님으로 작성하다가 삭제된 부분이 있어 추가하려다 보니 답글을 다셨네요.....그 부분과 함께 마저 올립니다. 죄송합니다.

ㅡ,.ㅡ;; wrote:
umean2me wrote:
이런이런....위 두글은 제글인데.......

괜히 남의 코딩가지고 왈가왈부하는거 같아서 ...
그럴수록님이 기분나빠서 더 안좋은소리만나올것이기때문에 ..
길게 얘기는 안하겠습니다.

그리 기분 나쁘지 않습니다. 다만 님께서 핵심은 빼고 님의 필요한 부분만 발췌해 그걸 제 주장이라 옮기시니 답답합니다. 님께서는 계속해서 핵심은 놓치시고 자신이 보려하는 부분만 님의 구미에 맞게 왜곡하여 보십니다." 이 때문에 기분이 정말 나쁜겁니다.

ㅡ,.ㅡ;; wrote:

님코드가 머 생소하리라고 말씀하셨는데 만일그렇다면 님이 여테 특정스타일의 코드만 구경하셨나보네요..
구조나 그어떤것에도 새롭다혹은 생소하다할만한것은 전혀없구요..그냥 일반적입니다....
제말이 그짓말인가 여기 오시는분들한테 투표해봐도 좋을듯하군요..아마도 대부분 그냥 일반적인C라고하지 마치 C++같다라던가 새롭다는사람은 없을껄요..
사실 소스보니 여기 있는 암호화 통신모듈이 님이 보여주신거랑 매우비슷하게 생긴게 여기도 있군요....소스제것이 아니기때문에 보여드릴수는없습니다.

님이 여유가 되신다면 .c 파일을 작성하시어 사용해 보시기 바랍니다. 간단히 사용을 해 보면..

main.c
int main(void)
{
  TCPACCEPTOR *tcpAcceptor = TCPAcceptor_Create();
  REACTOR *reactor = Reactor_Create(tcpAcceptor);

  TCPAcceptor_Init(tcpAcceptor, 6000);
  TCPAcceptor_Listen(tcpAcceptor);
  Reactor_Add(TCPAcceptor_GetTcpClient(tcpAcceptor));
  Reactor_run();
}

logic.c (비어있는 CallBack 함수 작성)

int CHandler_Open(CHANDLER *cHandler, TCPCLIENT *tcpClient, void *mainArg)
{
  USERARG *userArg = UserArg_Create(...);
  TCPACCEPTOR *tcpAcceptor = (TCPACCEPTOR *)mainArg;

  if (TCPAcceptor_GetFD(tcpAcceptor) == TCPClient_GetFD(tcpClient))
 {
    //새로 커넥션한 클라이언트 처리
    //이때 새로운 커넥션에 대해 Reactor은 CHandler_Open을 호출함
    TCPClient *newTcpClient = TCPAcceptor_Accept(tcpAcceptor);

    if (newTcpClient != NULL)
      Reactor_Add(CHandler_GetReactor(cHandler), newTcpClient);
    return 0;
 }

  CHandler_SetTimeOut(5000);
  CHandler_SetUserArg(USERARG *userArg);
  ......
  return 0;
}

int CHandler_Input(CHANDLER *cHandler, TCPCLIENT *tcpClient)
{
  CHandler_SetTimeOut(5000);
  //패킷처리....//
  return 0;
}

void CHandler_Close(CHANDLER *cHandler, TCPCLIENT *tcpClient)
{
  free(CHandler_GetUserArg(cHandler);
  .....
}

void CHandler_TimeOut(CHANDLER *cHandler, TCPCLIENT *tcpClient)
{
  //타임아웃이므로 커넥션 아웃 처리
  .....
  return -1;
}

(이 소스에 추상화등의 개념이 들어가면 참 편리하겠지만...)

이로써 대략 서버기능을 하는 놈이 만들어졌고 여기에 DB연결이라든가 다른 서버의 연결등에 추가함에 있어서 Reactor_Add 호출로만 한다면 개별적으로 관리할 수 있게 됩니다. 이것을 구조적 프로그래밍으로 나오는 개념으로 해보시고 말씀하십시요. OOP적 요소들이 숨어 있지 않는한 힘듭니다. 전에도 말씀드렸다 시피 Linux커널에도 이런 방법들이 적용됨을 발견할 수 있습니다.

ㅡ,.ㅡ;; wrote:

그리고 lib로 제공될것이라면 절대 내부를 까보는일은 없어야합니다. 아예그럴수 없기도 하구요..
그리고 책은 님이 좀더 보셔야할듯합니다.
보실때 C++을 왜 OOP 언어라고 하는지 보시고 다시한번 생각해보세요..

lib로 제공되는걸 까보는 일이 없는것은 당연한거 아닌지...그걸 모르고서 OOP를 했다고 주장하는건 아닙니다. 너무 어처구니 없는 말씀을 이 상황에서 늘어 놓으시니...좀 당혹스럽네요.

님이 왜 이렇게 말씀하시는지 님의 홈페이지를 보고서야 알것 같았습니다. 왜 제 헤더를 보고 일반적이라 말씀하시는 지 알 수 있더군요. 하지만 님께서는 OOP지향의 헤더와의 차이점을 아직 파악못하시고 계십니다. 좀 더 면밀히 생각해 보시고..더구나 C++을 꼭 경험해 보라고 하고 싶습니다.

특히나 클래스의 메소드 작성은 내부구조에 의한 규정이 아니라 객체지향적이니 그 객체가 하는 행위에서 관점을 바라 보는 것입니다. 그만큼 클래스의 이름을 짓는것도 중요한 일입니다. 이런 미묘한 차이를 님께서 잘 파악 못하고 계십니다. 이런 부분들이 님의 헤더에는 부분적으로만 적용되어있는 것을 볼 수 있었습니다.

한가지 라이브러리 뿐만 아니라 여러 복잡한 라이브러리를 사용했을때 구조체 안에 여러가지의 구조체가 쌓이고 또 이런것들이 서로 융합하면서 생기는 복잡함을 C가 가지는 문법적 제한으로는 풀어내기가 여간 힘든게 아닙니다. 물론 C++보다 말입니다. 이런 부분들의 관리를 객체에 역할과 책임을 분명히 시키어 보다 복잡한 프로그래밍 환경에서 원할한 관리를 해주어 보다 빠르고 지능적이며 추상화나나 필요한 패턴등을 통해 유지보수에 탁월한 성능을 내는 것입니다. 또 객체를 통해 전체로 보여질 수 있는 문제를 단순화 시킴으로써 복잡해 보이는 구조를 상당히 단순하게 보여줍니다.

Quote:

예를 들어 동시접속수 3000정도의 유저와 유저가 가지는 종류별 아이템과 개인정보등을 구조체가 가지는 특징으로만 관리하고 쓰레드에 DB연동에 타 서버와의 메세지 연동등을 C로만 하게 된다면 코드의 복잡도가 상당하게 올라가게 됩니다.

이때에는 라이브러리 수준이 아니라 프레임웍위에 프레임웍위에..구조체간 협업 방법등이 구조체 수준에서 해결하려하면 할수록 난항을 격고 맙니다.

특히나 쓰레드 사용에 있어서 각 구조체간 정보를 서로 공유한다거나 업데이트 하는 상황에서 C의 함수레벨에서는 코드의 복잡도가 수배 이상 증가합니다.

결코 OOP나 C++, 자바를 많은 부분에서 경험하지 못하시고 함부로 논하시는 것은 잘못된 부분이라고 짚고 넘어 가고 싶네요.

ㅡ,.ㅡ;; wrote:

딴지일지 모릅니다만..
머하러 어렵게 C로 C++ 흉내냅니까... 그냥 C++ 사용하면되지..
C++ 흉내냈다고 해봤자 C++ 같지도 않구요..
C로는 그냥 C 처럼 짜는것이 가장 자연스럽습니다.

누가 그런코드로 짜놓은 소스가 있는데요..
보면 소스다지우고 싶습니다..^^;
메모리 오류도 많을뿐만아니라 메모리 할당해제도 재대로 안되있거든요..함수재사용은 매우안되고 있고..
문제는 오류를 잡아내기 무척힘듭니다.또한속도 무지 늦고..
시스템 리소스 엄청많이먹네요..

OOP의 캡슐화.. 이건 캡슐다까봐야할 실정이네요..이런건 절대 하지맙시다..ㅎㅎ

님께서 이런 문제를 격는것은 팀구성의 문제이지 OOP의 문제가 아닙니다. 코딩컨벤션이나 기타 룰들...님의 팀문제를 OOP의 탓으로 해서 다른이들에게 잘못된 정보를 전달하시는 것을 보고 OOP를 하시는 분들이 딴지를 거는 겁니다. 이걸 아셨으면 좋겠군요.

다시한번 말씀드리지만 잘못된 클래스라면 라이브러리화 되어 있다 하더라도 까내야만 합니다. 또 라이브러리에 대한 책임이 라이브러리 제작자 또는 인수인계자에게 있는 것이지 그것을 응용하여 만드는 사람에게 있는것이 아닙니다.

OOP에서 둘에 있어서는 확실한 인터페이스만 규정되어 있으면 되는 것입니다. C에서 이런 개념이 불확실하죠. C에서는 보통 함수 추가하기를 일반적으로 우습게 여깁니다만 C++에서는 객체간의 통신 프로토콜로써 규정되어 그것이 엄격하게 작동해야만 합니다.(물론 퍼블릭 메소드들을 말하는 겁니다.) 따라서 설계가 중요한 이슈가 되는것입니다.

전 유닉스쪽의 C/C++만을 합니다만 개인적으로 자바진영이 부러운 것은 아키텍처패턴, 디자인패턴등의 여러 서적입니다. 뭐 C++이 봐도 상관 없지만 부러운 이유는 언어에 대한 대중성과 의식이 자바만큼 충실했으면 하는 바램때문이죠.

익명 사용자의 이미지

저는 ㅡ,.ㅡ;; 님의 글은 그냥 스킵하고 봅니다. 쓸만한 정보나 깊이있는 생각이 올라왔던 적은 한번도 없었던것 같군요.

ㅡ,.ㅡ;;의 이미지

umean2me wrote:

결코 OOP나 C++, 자바를 많은 부분에서 경험하지 못하시고 함부로 논하시는 것은 잘못된 부분이라고 짚고 넘어 가고 싶네요.


어이없네요..
님은 토론을 하는게 아니군요..

님 몇년하셨나요.. 제가 안해보고 말한다고 생각하시나요..
그렇게 상대를 속단하고 있으니까 그런말이 나오죠..
님한테 그런소리들을정도는 아니거든요..
님하신걸보니 님보다 적게하진 않았을듯하군요..

그리고 자신이 버젓이 평가해달라고 올려놓고..
평가한사람을오히려 이런식으로 공격할것같으면 머하러 올렸나요..

그리고 자신의 프로그램에 누구나 애착을 가지고 하는건 알지만
그렇다고 남도 그렇게 봐주리라고는는 생각하지마세요..
그냥 제가볼때는 별반차이 없다였습니다.

그리고 OOP혹은 그어떤것도 그것이 절대적이라는 생각은 크게 잘못된것입니다.

슬데없는 이런글은 그만쓰는게 좋겠군요..
그냥 제가 님소스본게 잘못이었습니다..


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

ㅡ,.ㅡ;;의 이미지

Anonymous wrote:
저는 ㅡ,.ㅡ;; 님의 글은 그냥 스킵하고 봅니다. 쓸만한 정보나 깊이있는 생각이 올라왔던 적은 한번도 없었던것 같군요.

숨어서 호박씨.. 까네요..ㅎㅎ
양심이 부끄러우실겁니다. 머.. 자게 때문에 그러실건데.
좀지저분하시군요..


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

익명 사용자의 이미지

ㅡ,.ㅡ;; wrote:
umean2me wrote:

결코 OOP나 C++, 자바를 많은 부분에서 경험하지 못하시고 함부로 논하시는 것은 잘못된 부분이라고 짚고 넘어 가고 싶네요.


어이없네요..
님은 토론을 하는게 아니군요..

님 몇년하셨나요.. 제가 안해보고 말한다고 생각하시나요..
그렇게 상대를 속단하고 있으니까 그런말이 나오죠..
님한테 그런소리들을정도는 아니거든요..
님하신걸보니 님보다 적게하진 않았을듯하군요..

그리고 자신이 버젓이 평가해달라고 올려놓고..
평가한사람을오히려 이런식으로 공격할것같으면 머하러 올렸나요..

그리고 자신의 프로그램에 누구나 애착을 가지고 하는건 알지만
그렇다고 남도 그렇게 봐주리라고는는 생각하지마세요..
그냥 제가볼때는 별반차이 없다였습니다.

그리고 OOP혹은 그어떤것도 그것이 절대적이라는 생각은 크게 잘못된것입니다.

슬데없는 이런글은 그만쓰는게 좋겠군요..
그냥 제가 님소스본게 잘못이었습니다..

ㅡ,.ㅡ;; 님께서 실력은 보여주지 않으시고, 언제나 남보다 실력이 좋다고 은연중에 말씀하고 계십니다.

어투또한 토론 아닌 딴지 입니다.

평가는 하신적 없고 공격만 하고 계시구요.

Quote:
슬데없는 이런글은 그만쓰는게 좋겠군요..

제발 그러시길 바랍니다.

ps. 딴지였습니다. 이런식으로 글 올리는걸 반성하며 잠금요청합니다. 죄송합니다.

cppig1995의 이미지

완전히 알려지지 않은 구조체

C 언어로 은닉 (Encapsulation) 을 구현하는 쓸모있는 방법입니다.
비슷한 방법이 C++ 에서 재번역 의존성 제거법으로도 쓰이고요.
(Herb Sutter 님의 Exceptional C++ 참고)

List of "foo.c" :

#include "bar.h"

int main()
{
   BAR *bar = create_bar();
   use_bar(bar);
   remove_bar(bar);
   return 0;
}

List of "bar.c" :

#include "bar.h"

struct BAR_
{
  int somedata1;
  int somedata2;
  void *memory;
};
typedef struct BAR_ BAR;

BAR *create_bar() { static BAR b; return &b; }
void use_bar(BAR *) {  }
void remove_bar(BAR *) { }

List of "bar.h" :

struct BAR_;

struct BAR_ *create_bar();
void use_bar(struct BAR_ *);
void remove_bar(struct BAR_ *);

C 써본 지 하도 오래되어 잘 모르겠지만,
대충 이 정도면 충분한 것으로 알고 있습니다.
이의 제기 해주세요.

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

corba의 이미지

돼지군님 께서 좋은 예를 들어 주셨네요.

Win32API의 핸들도 이렇게 되어 있었던 것 같네요.

OOP가 아닌 곳에서도 이런 개념은 오래 전에 쓰이고 있었죠.

좀 더 추상적으로 보면 OOP든 구조적프로그래밍이든 노련한 프로그래머는 같은 것을 지향하는 것 같습니다.

애써 구분할 필요가 있나 싶네요.

p.s : C 써본지가 하도 오래 되었다는... ;ㅁ; 대체 몇살때 C를 배우신 겁니까... OTL

익명 사용자의 이미지

괜히 끼어들어 죄송합니다만....

OOP 의 정의를 알고 계시긴 한겁니까?
무엇이 OOP 다운것이며, 논의되고 있는 코드가 OOP 적인지를 확인하려면,
일단 OOP 가 무엇인지 정의를 생각해보고, 그렇게 정의된 기준에 코드나 의견이 부합하는지를 비교해보면 될 것을...
OOP 가 뭔지 논리적으로 비교 제시하지 않고 괜히 감정싸움에 인신공격으로까지 번지는 모습이 안되보여 지나가다 의견을 적습니다.

간단히 말해... 무엇이 OOP 인가? 단순히 캡슐화를 제공하는 정도라면 그것은 데이터추상화이고, OOP 라 일컫기 위해서는 거기에 덧붙여 상속과 다형성 및 기타등등의 특징이 포함되어야 합니다.
학창시절에 C++ 창시자가 쓴 책의 Chapter 0 에서 읽었던 기억이 있군요.

프로그래밍 패러다임을 발전순서대로 아주 잘 요약해서 설명해 놓은 부분이 있으니, 꼭 일독하시길 권합니다. (물론 읽어보셨지만 잊고 계시리라 생각합니다)

너도 나도 같은 업을 가진 동료들끼리 괜히 싸우지말고, 토론이 타인에게도 발전적으로 진행되면 좋겠습니다. 감사합니다.

익명 사용자의 이미지

OOP 정의가 한마디로 정의되기가 쉽지가 않을 텐데~....

출처 : http://lastmind.net/2005/03/object_thinking.html

Object Thinking

Quote:

'Introduction to Software Engineering' 과목에서는 Object-Oriented Design을 가르친다. 간단한 정의와 함께, UML design 과정에서 use case로부터 object를 골라내서 class diagram을 그리는 법은 가르친다. 하지만, 아무도 object-oriented programming paradigm 뒤에 들어있는 생각을 가르쳐주지는 않는다. (물론, 다룰 주제가 많은 software engineering 과목에서 OOP를 깊게 설명하기는 어렵다.)

OOP language를 쓰는 것은 일종의 유행이다. 모두들 그 이유를 잘 알지도 못하면서 OOP를 선호한다. 심지어는 그것이 무엇인지도 모르면서 말이다. 사실, 나도 그런 사람들 중의 하나였고, C를 사용한 procedural programming paradigm에 익숙해지고 난 후, 주로 OOP language (C++, Java, Python, Ruby, ...)를 사용하기 시작하면서, 계속 던지게 되는 질문은 OOP란 무엇인가, 대체 procedural programming paradigm보다 object-oriented programming paradigm이 무엇이 우월한가라는 것이었다.

'Object Thinking'은 이러한 질문에 답변해주는 책이다. 즉, SE 과목에서 한두페이지의 페이지에 설명해놓은 것을 이 책에서는 300페이지에 걸쳐서 설명해놓은 책이다. OOP는 technique이 아니라 paradigm이다. 생각하는 방식은 누군가의 간단한 한마디 말로는 바뀌기 힘들다. (물론 그런 경우도 있다.) 'Object Thinking'은 'object philosophy', 'object culture'란 말을 도입한다. 당연하게도, 사상(thinking)에는 철학(philosophy)이 전제되고, 문화(culture)가 따르고, 역사(history)를 가지기 마련이다. object thinking의 중심 원리(principle)들과 역사를 설명하고, 다른 philosophy와 culture와 대조를 함으로써 object thinking이 무엇인지가 조금씩 드러난다.

이 책에서는 단지 OOP가 무엇인지에 대해서만 다루고 있는 것은 아니다. OOP 외에도 software development의 여러가지 생각(thought)들을 object culture의 범주안으로 통합시킨다. 특히, XP와 같은 Agile software development가 여기에 해당된다. 따라서, 이 책에서 얘기하는 'object thinking'은 단지 OOP가 아닌 것이다.

또, 이 책에서 설명하는 OOP는 Booch를 중심으로 표준화된 전통적인 SE 진영의 OOP와는 조금씩 다르게 보인다. 여러번 책에서 언급되는 Smalltalk community 쪽(이를 공식적으로는 어떻게 지칭하는지 모르겠다.)에서 발전된 생각으로 보인다. 한가지 예로, OOP에 관한 여러 책들에서 object란 data와 algorithm의 결합이라고 지칭하지만, 이 책에서는 그러한 생각을 과감하게 거부한다. object란 behavior로 정의된다고 주장한다. 이러한 생각 한가지만으로도 object design에는 엄청난 영향을 미치게된다고 생각된다. (이 주제에 대해서는 나중에 따로 다뤄보겠다.)

아직 번역서가 없지만, 여력이 된다면, 또는 언젠가 번역이 된다면, 반드시 읽어보라고 추천해주고 싶은 책이다. 시간이 난다면, 이 책에서 인상 깊었던 생각들을 조금씩 블로그에 정리해볼까도 한다.

익명 사용자의 이미지

Anonymous wrote:
OOP 정의가 한마디로 정의되기가 쉽지가 않을 텐데~....

출처 : http://lastmind.net/2005/03/object_thinking.html

Object Thinking

Quote:

'Introduction to Software Engineering' 과목에서는 Object-Oriented Design을 가르친다. 간단한 정의와 함께, UML design 과정에서 use case로부터 object를 골라내서 class diagram을 그리는 법은 가르친다. 하지만, 아무도 object-oriented programming paradigm 뒤에 들어있는 생각을 가르쳐주지는 않는다. (물론, 다룰 주제가 많은 software engineering 과목에서 OOP를 깊게 설명하기는 어렵다.)

OOP language를 쓰는 것은 일종의 유행이다. 모두들 그 이유를 잘 알지도 못하면서 OOP를 선호한다. 심지어는 그것이 무엇인지도 모르면서 말이다. 사실, 나도 그런 사람들 중의 하나였고, C를 사용한 procedural programming paradigm에 익숙해지고 난 후, 주로 OOP language (C++, Java, Python, Ruby, ...)를 사용하기 시작하면서, 계속 던지게 되는 질문은 OOP란 무엇인가, 대체 procedural programming paradigm보다 object-oriented programming paradigm이 무엇이 우월한가라는 것이었다.

'Object Thinking'은 이러한 질문에 답변해주는 책이다. 즉, SE 과목에서 한두페이지의 페이지에 설명해놓은 것을 이 책에서는 300페이지에 걸쳐서 설명해놓은 책이다. OOP는 technique이 아니라 paradigm이다. 생각하는 방식은 누군가의 간단한 한마디 말로는 바뀌기 힘들다. (물론 그런 경우도 있다.) 'Object Thinking'은 'object philosophy', 'object culture'란 말을 도입한다. 당연하게도, 사상(thinking)에는 철학(philosophy)이 전제되고, 문화(culture)가 따르고, 역사(history)를 가지기 마련이다. object thinking의 중심 원리(principle)들과 역사를 설명하고, 다른 philosophy와 culture와 대조를 함으로써 object thinking이 무엇인지가 조금씩 드러난다.

이 책에서는 단지 OOP가 무엇인지에 대해서만 다루고 있는 것은 아니다. OOP 외에도 software development의 여러가지 생각(thought)들을 object culture의 범주안으로 통합시킨다. 특히, XP와 같은 Agile software development가 여기에 해당된다. 따라서, 이 책에서 얘기하는 'object thinking'은 단지 OOP가 아닌 것이다.

또, 이 책에서 설명하는 OOP는 Booch를 중심으로 표준화된 전통적인 SE 진영의 OOP와는 조금씩 다르게 보인다. 여러번 책에서 언급되는 Smalltalk community 쪽(이를 공식적으로는 어떻게 지칭하는지 모르겠다.)에서 발전된 생각으로 보인다. 한가지 예로, OOP에 관한 여러 책들에서 object란 data와 algorithm의 결합이라고 지칭하지만, 이 책에서는 그러한 생각을 과감하게 거부한다. object란 behavior로 정의된다고 주장한다. 이러한 생각 한가지만으로도 object design에는 엄청난 영향을 미치게된다고 생각된다. (이 주제에 대해서는 나중에 따로 다뤄보겠다.)

아직 번역서가 없지만, 여력이 된다면, 또는 언젠가 번역이 된다면, 반드시 읽어보라고 추천해주고 싶은 책이다. 시간이 난다면, 이 책에서 인상 깊었던 생각들을 조금씩 블로그에 정리해볼까도 한다.

OOP 가 한마디로 정의하기 어려운 아주 어렵고도 심오한-_- 개념이니 저책을 사서 봐야지만 한다는 뭐 그런류의 글인가요?
위의 책광고-_-에서 언급한 OOP 의 개념비스무리 한 것은 딱 한줄이군요.
'OOP에 관한 여러 책들에서 object란 data와 algorithm의 결합이라고 지칭하지만' <- 이부분....
그나마도 부정확하군요.
명확하지 않은 개념은 그저 도나 기에 관심있는 분들에게나 필요한 것입니다.

corba의 이미지

OOP에 대해서 정의 하기 힘들다면 자기가 해놓은 설계가 OCP, LSP, SRP, DIP, ISP를 얼마나 잘 지키고 있는지 검증해 보는 방법으로 접근하는건 어떨까요 ?

handrake의 이미지

제가 맨 처음 이 글타래를 연 까닭은 윗분께서 말씀하셨듯이 C로 OOP를 할 수 있나? 하는 궁금증에서 였습니다.
왜 C++이 아니고 C냐? 하시면 사실은 제가 운영체제 제작에 관심이(관심만?) 있어서 그렇습니다.
많은 osdev 사이트를 돌아다니고 하다보면 초보자(!)에게는 C가 커널 제작에 다른 어떤 언어보다
유리할 가능성이 크다는 것을 많이 보았습니다. (많은 튜토리얼들과 예제들이 C로 짜여 있음으로부터 시작해서)
그런데 어느 분이 지적하신 것처럼 VFS에서는 OOP 개념이 필요하기도 할 때가 있어서 C로 OOP가 가능한가?
만약 가능하다면 어떤 식의 구현이 좋은가를 묻고자 질문을 하였습니다만, 질문이 명확하지 않아서 많은 분들이
혼란을 겪으신 것 같습니다. 그 점에 사과드립니다. (__)

a를 파라미터로 넘기는 방법도 물론 좋지만 문법적으로 좀더 C++에 가까운 것은 무엇일까? 하는 호기심에
며칠동안 계속 생각을 해 보았습니다만, 아둔한 제 머리의 한계로는 다음의 코드가 가장 나을 것이라는 결론을 내렸습니다.

#include<stdio.h>

void *this = 0;

void inc_one();
void dec_one();

typedef void (*void_func)(void);

typedef struct my_str {
        int iLen;
        void_func inc;
        void_func dec;
}my_str;

my_str* init_my_str()
{
        my_str *new_my_str = (my_str*) malloc(sizeof(my_str));
        new_my_str->inc = &inc_one;
        new_my_str->dec = &dec_one;
        new_my_str->iLen = 0;
        return new_my_str;
}

void inc_one()
{
        ((my_str*)this)->iLen++;
}

void dec_one()
{
        ((my_str*)this)->iLen--;
}

my_str* SEL (my_str* my_str_this)
{
        this = my_str_this;
        return my_str_this;
}

main()
{
        my_str *a = init_my_str();
        printf("a->iLen = %d\n", a->iLen);
        SEL(a)->inc();
        printf("a->iLen = %d\n", a->iLen);
}
moonzoo의 이미지

my_str* SEL (my_str* my_str_this) 
{ 
        this = my_str_this; 
        return my_str_this; 
} 

main() 
{ 
        my_str *a = init_my_str(); 
        printf("a->iLen = %d\n", a->iLen); 
        SEL(a)->inc(); 
        printf("a->iLen = %d\n", a->iLen); 
} 

SEL의 return type 및 argument type이 my_str * 로 고정되어 있어서,

여러 객체 TYPE을 다룰 수 없어 보입니다..

여러 객체 TYPE마다 또다른 SEL을 만들기에는 너무 부담되어 보이고요.

ㅡ,.ㅡ;;의 이미지

handrake wrote:
제가 맨 처음 이 글타래를 연 까닭은 윗분께서 말씀하셨듯이 C로 OOP를 할 수 있나? 하는 궁금증에서 였습니다.
왜 C++이 아니고 C냐? 하시면 사실은 제가 운영체제 제작에 관심이(관심만?) 있어서 그렇습니다.
많은 osdev 사이트를 돌아다니고 하다보면 초보자(!)에게는 C가 커널 제작에 다른 어떤 언어보다
유리할 가능성이 크다는 것을 많이 보았습니다. (많은 튜토리얼들과 예제들이 C로 짜여 있음으로부터 시작해서)
그런데 어느 분이 지적하신 것처럼 VFS에서는 OOP 개념이 필요하기도 할 때가 있어서 C로 OOP가 가능한가?
만약 가능하다면 어떤 식의 구현이 좋은가를 묻고자 질문을 하였습니다만, 질문이 명확하지 않아서 많은 분들이
혼란을 겪으신 것 같습니다. 그 점에 사과드립니다. (__)

a를 파라미터로 넘기는 방법도 물론 좋지만 문법적으로 좀더 C++에 가까운 것은 무엇일까? 하는 호기심에
며칠동안 계속 생각을 해 보았습니다만, 아둔한 제 머리의 한계로는 다음의 코드가 가장 나을 것이라는 결론을 내렸습니다.

#include<stdio.h>

void *this = 0;

void inc_one();
void dec_one();

typedef void (*void_func)(void);

typedef struct my_str {
        int iLen;
        void_func inc;
        void_func dec;
}my_str;

my_str* init_my_str()
{
        my_str *new_my_str = (my_str*) malloc(sizeof(my_str));
        new_my_str->inc = &inc_one;
        new_my_str->dec = &dec_one;
        new_my_str->iLen = 0;
        return new_my_str;
}

void inc_one()
{
        ((my_str*)this)->iLen++;
}

void dec_one()
{
        ((my_str*)this)->iLen--;
}

my_str* SEL (my_str* my_str_this)
{
        this = my_str_this;
        return my_str_this;
}

main()
{
        my_str *a = init_my_str();
        printf("a->iLen = %d\n", a->iLen);
        SEL(a)->inc();
        printf("a->iLen = %d\n", a->iLen);
}

고민 하신부분이 아이디어는 좋았는데..
일반화하여 사용하기는 힘들겠군요..
좀 복잡해질경우 치명적인 문제가 발생할수 있겠는데요...

그리고 함수를 한번더 거쳐야하는 번거러움도 있네요.(가랑비에 옷젖듯이..)
표현법에도 그다지 유리하다는생각은....
약간 다른방법으로 매크로를 적용해보는것도 좋을듯하네요..


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

익명 사용자의 이미지

Anonymous wrote:
... 전략
OOP 가 한마디로 정의하기 어려운 아주 어렵고도 심오한-_- 개념이니 저책을 사서 봐야지만 한다는 뭐 그런류의 글인가요?
위의 책광고-_-에서 언급한 OOP 의 개념비스무리 한 것은 딱 한줄이군요.
'OOP에 관한 여러 책들에서 object란 data와 algorithm의 결합이라고 지칭하지만' <- 이부분....
그나마도 부정확하군요.

명확하지 않은 개념은 그저 도나 기에 관심있는 분들에게나 필요한 것입니다.

글 좀 똑바로 읽읍시다. 난독증인가???

Quote:
또, 이 책에서 설명하는 OOP는 Booch를 중심으로 표준화된 전통적인 SE 진영의 OOP와는 조금씩 다르게 보인다. 여러번 책에서 언급되는 Smalltalk community 쪽(이를 공식적으로는 어떻게 지칭하는지 모르겠다.)에서 발전된 생각으로 보인다. 한가지 예로, OOP에 관한 여러 책들에서 object란 data와 algorithm의 결합이라고 지칭하지만, 이 책에서는 그러한 생각을 과감하게 거부한다. object란 behavior로 정의된다고 주장한다. 이러한 생각 한가지만으로도 object design에는 엄청난 영향을 미치게된다고 생각된다. (이 주제에 대해서는 나중에 따로 다뤄보겠다.)
lovewar의 이미지

handrake wrote:
제가 맨 처음 이 글타래를 연 까닭은 윗분께서 말씀하셨듯이 C로 OOP를 할 수 있나? 하는 궁금증에서 였습니다.
왜 C++이 아니고 C냐? 하시면 사실은 제가 운영체제 제작에 관심이(관심만?) 있어서 그렇습니다.
많은 osdev 사이트를 돌아다니고 하다보면 초보자(!)에게는 C가 커널 제작에 다른 어떤 언어보다
유리할 가능성이 크다는 것을 많이 보았습니다. (많은 튜토리얼들과 예제들이 C로 짜여 있음으로부터 시작해서)
그런데 어느 분이 지적하신 것처럼 VFS에서는 OOP 개념이 필요하기도 할 때가 있어서 C로 OOP가 가능한가?
만약 가능하다면 어떤 식의 구현이 좋은가를 묻고자 질문을 하였습니다만, 질문이 명확하지 않아서 많은 분들이
혼란을 겪으신 것 같습니다. 그 점에 사과드립니다. (__)

a를 파라미터로 넘기는 방법도 물론 좋지만 문법적으로 좀더 C++에 가까운 것은 무엇일까? 하는 호기심에
며칠동안 계속 생각을 해 보았습니다만, 아둔한 제 머리의 한계로는 다음의 코드가 가장 나을 것이라는 결론을 내렸습니다.

다음과 같이 수정해 보았습니다.

#include<stdio.h>
#include <stdlib.h>

static void inc_one();
static void dec_one();

typedef void (*ptr_func)(void);

typedef struct my_str {
    void * base;
    int iLen;
    ptr_func inc;
    ptr_func dec;
}my_str;

static my_str *this = 0;

extern my_str* init_my_str()
{
    this = (my_str *) malloc(sizeof(my_str));
    this->inc = &inc_one;
    this->dec = &dec_one;
    this->iLen = 0;
    return this;
}

static void inc_one()
{
    this->iLen++;
}

static void dec_one()
{
    this->iLen--;
}

int main(void)
{
    my_str *a = init_my_str();
    printf("a->iLen = %d\n", a->iLen);
    a->inc();
    printf("a->iLen = %d\n", a->iLen);
    return 0;
}

클래스 하나당 .c 파일을 하나씩 만들어야 한다는 생각에 속성을
추가하고 this에도 static 속성을 추가했습니다.

irondog의 이미지

lovewar wrote:
handrake wrote:
제가 맨 처음 이 글타래를 연 까닭은 윗분께서 말씀하셨듯이 C로 OOP를 할 수 있나? 하는 궁금증에서 였습니다.
왜 C++이 아니고 C냐? 하시면 사실은 제가 운영체제 제작에 관심이(관심만?) 있어서 그렇습니다.
많은 osdev 사이트를 돌아다니고 하다보면 초보자(!)에게는 C가 커널 제작에 다른 어떤 언어보다
유리할 가능성이 크다는 것을 많이 보았습니다. (많은 튜토리얼들과 예제들이 C로 짜여 있음으로부터 시작해서)
그런데 어느 분이 지적하신 것처럼 VFS에서는 OOP 개념이 필요하기도 할 때가 있어서 C로 OOP가 가능한가?
만약 가능하다면 어떤 식의 구현이 좋은가를 묻고자 질문을 하였습니다만, 질문이 명확하지 않아서 많은 분들이
혼란을 겪으신 것 같습니다. 그 점에 사과드립니다. (__)

a를 파라미터로 넘기는 방법도 물론 좋지만 문법적으로 좀더 C++에 가까운 것은 무엇일까? 하는 호기심에
며칠동안 계속 생각을 해 보았습니다만, 아둔한 제 머리의 한계로는 다음의 코드가 가장 나을 것이라는 결론을 내렸습니다.

다음과 같이 수정해 보았습니다.

#include<stdio.h>
#include <stdlib.h>

static void inc_one();
static void dec_one();

typedef void (*ptr_func)(void);

typedef struct my_str {
    void * base;
    int iLen;
    ptr_func inc;
    ptr_func dec;
}my_str;

static my_str *this = 0;

extern my_str* init_my_str()
{
    this = (my_str *) malloc(sizeof(my_str));
    this->inc = &inc_one;
    this->dec = &dec_one;
    this->iLen = 0;
    return this;
}

static void inc_one()
{
    this->iLen++;
}

static void dec_one()
{
    this->iLen--;
}

int main(void)
{
    my_str *a = init_my_str();
    printf("a->iLen = %d\n", a->iLen);
    a->inc();
    printf("a->iLen = %d\n", a->iLen);
    return 0;
}

클래스 하나당 .c 파일을 하나씩 만들어야 한다는 생각에 속성을
추가하고 this에도 static 속성을 추가했습니다.

뭔가 잘 못 된게 아닐까요? 이전 코드가 좀 더 정확한 것 같은데...
이렇게 되면...

int main(void)
{
    my_str *a = init_my_str();
    my_str *b = init_my_str();

    printf("a->iLen = %d\n", a->iLen);
    a->inc();
    b->inc();
    printf("a->iLen = %d\n", a->iLen);
    return 0;
}

클래스의 두번째 인스턴스가 만들어지면 첫번째 인스턴스의 동작에 문제가 생기지 않나요? a->inc() b의 자료를 참조하게 될듯 싶은데...

lovewar의 이미지

irondog wrote:

뭔가 잘 못 된게 아닐까요? 이전 코드가 좀 더 정확한 것 같은데...
이렇게 되면...
int main(void)
{
    my_str *a = init_my_str();
    my_str *b = init_my_str();

    printf("a->iLen = %d\n", a->iLen);
    a->inc();
    b->inc();
    printf("a->iLen = %d\n", a->iLen);
    return 0;
}

클래스의 두번째 인스턴스가 만들어지면 첫번째 인스턴스의 동작에 문제가 생기지 않나요? a->inc() b의 자료를 참조하게 될듯 싶은데...

녜, 잘못되었습니다. 지적 감사합니다.
handrake 님코드에 속성만 추가해 봐았습니다.
handrake 님이 고민 많이 하신것 같습니다.

#include<stdio.h>

staic void *this = 0;

staic void inc_one();
staic void dec_one();

typedef void (*void_func)(void);

typedef struct my_str {
        int iLen;
        void_func inc;
        void_func dec;
}my_str;

extern my_str* init_my_str()
{
        my_str *new_my_str = (my_str*) malloc(sizeof(my_str));
        new_my_str->inc = &inc_one;
        new_my_str->dec = &dec_one;
        new_my_str->iLen = 0;
        return new_my_str;
}

staic void inc_one()
{
        ((my_str*)this)->iLen++;
}

staic void dec_one()
{
        ((my_str*)this)->iLen--;
}

extern my_str* SEL (my_str* my_str_this)
{
        this = my_str_this;
        return my_str_this;
}

int main(void)
{
        my_str *a = init_my_str();
        printf("a->iLen = %d\n", a->iLen);
        SEL(a)->inc();
        printf("a->iLen = %d\n", a->iLen);
        return 0;
}

아래코드는 this란 static 변수를 제거하고, 구조체에 대한 reference를 파라미터를 사용해서 만들었습니다.

이기법은 C를 C++로 흉내낼때 사용하는 기법으로 나온것을
따라 했습니다.

#include<stdio.h>
#include <stdlib.h>


typedef struct my_str my_str_t;

typedef void (*ptr_func)(my_str_t * this);

struct my_str {
    void * base;
    int iLen;
    ptr_func inc;
    ptr_func dec;
};

static void inc_one(my_str_t * this);
static void dec_one(my_str_t * this);

extern my_str_t * init_my_str()
{
    my_str_t * instance = (my_str_t *) malloc(sizeof(my_str_t));
    instance->inc = &inc_one;
    instance->dec = &dec_one;
    instance->iLen = 0;
    return instance;
}

static void inc_one(my_str_t * this)
{
    this->iLen++;
}

static void dec_one(my_str_t * this)
{
    this->iLen--;
}

int main(void)
{
    my_str_t *a = init_my_str();
    my_str_t *b = init_my_str();
    printf("a->iLen = %d\n", a->iLen);
    a->inc(a);
    b->dec(b);
    printf("a->iLen = %d\n", a->iLen);
    printf("b->iLen = %d\n", b->iLen);
    return 0;
}
handrake의 이미지

moonzoo wrote:
my_str* SEL (my_str* my_str_this) 
{ 
        this = my_str_this; 
        return my_str_this; 
} 

main() 
{ 
        my_str *a = init_my_str(); 
        printf("a->iLen = %d\n", a->iLen); 
        SEL(a)->inc(); 
        printf("a->iLen = %d\n", a->iLen); 
} 

SEL의 return type 및 argument type이 my_str * 로 고정되어 있어서,

여러 객체 TYPE을 다룰 수 없어 보입니다..

여러 객체 TYPE마다 또다른 SEL을 만들기에는 너무 부담되어 보이고요.

그건 저도 더 이상 좋은 방법을 찾기가 어렵더군요...

Quote:
고민 하신부분이 아이디어는 좋았는데..
일반화하여 사용하기는 힘들겠군요..
좀 복잡해질경우 치명적인 문제가 발생할수 있겠는데요...

그리고 함수를 한번더 거쳐야하는 번거러움도 있네요.(가랑비에 옷젖듯이..)
표현법에도 그다지 유리하다는생각은....
약간 다른방법으로 매크로를 적용해보는것도 좋을듯하네요..

ㅡ,.ㅡ;;님 말씀에 따라 매크로를 만들어 보았습니다만, 다음과 같이 밖에 못만들겠더군요. :oops:

#define SEL ( (this) = (a) )

그런데 이렇게 만들면 사용할 때 아래와 같이 매번 type-casting을 해줘야 하는 불편이 있는 것 같습니다.

((my_str*)SEL(a))->inc()

혹시 해주지 않고도 사용할수 있는 방법이 있을까요?

전웅의 이미지

lovewar wrote:
아래코드는 this란 static 변수를 제거하고, 구조체에 대한 reference를 파라미터를 사용해서 만들었습니다.

이기법은 C를 C++로 흉내낼때 사용하는 기법으로 나온것을
따라 했습니다.

...
    a->inc(a);
    b->dec(b);
...

결국은 원점으로 돌아오게 되었습니다.

handrake wrote:
그렇긴 그렇습니다만, 매크로로

#define SEL ( (this) = (a) )

물론,

#define SEL(a) (this = (a))
void *this;

를 의도하신 것이라 생각합니다.

handrake wrote:
이렇게 만들면 사용할 때 아래와 같이 매번 type-casting을 해줘야 하는 불편이 있는거 같아서요.

((my_str*)SEL(a))->inc()

혹시 해주지 않고도 사용할수 있는 방법이 있을까요?

잠시 외도를 했던 논의가 다시 정상궤도로 돌아오게 되어 기쁩니다. ;-)

제 생각에는 C 로 프로그래밍을 하면서 반드시 C++ 의 "형식"을 빌려야 할
필요를 크게 느끼지 못해 this 에 해당하는 바를 인자로 전달해 주는
방식이면 충분히 좋다고 생각합니다만, "비표준 확장"을 사용해서라도
반드시 SEL() 매크로를 사용하고 싶으시다면 다음과 같은 방법도 있긴
있습니다.

#define SEL(a) ((typeof (a)) (this = (a)))

흠... "비표준 확장"에 "전역 변수"라...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

lovewar의 이미지

전웅 wrote:
lovewar wrote:
아래코드는 this란 static 변수를 제거하고, 구조체에 대한 reference를 파라미터를 사용해서 만들었습니다.

이기법은 C를 C++로 흉내낼때 사용하는 기법으로 나온것을
따라 했습니다.

...
    a->inc(a);
    b->dec(b);
...

결국은 원점으로 돌아오게 되었습니다.

위글들을 다 읽지 못했습니다 . 죄송합니다.

전웅 wrote:

코드:
#define SEL(a) ((typeof (a)) (this = (a)))

흠... "비표준 확장"에 "전역 변수"라...

쓰레드 개념이 필요할때는 다른 기법(lock-unlock)들도 같이 있어야 할것 같습니다.

handrake의 이미지

다시 한번 삽질해 보니 다음것이 좀 더 나은거 같습니다. 매크로를 써서 type에 구애를 받지 않게 해보았습니다.

#include<stdio.h>

void *this = 0;

void inc_one();
void dec_one();

#define SEL(my_str_this) (((this = (my_str_this))==0)?(0):(my_str_this))

typedef void (*void_func)(void);

typedef struct my_str {
        int iLen;
        void_func inc;
        void_func dec;
}my_str;

my_str* init_my_str()
{
        my_str *new_my_str = (my_str*) malloc(sizeof(my_str));
        new_my_str->inc = &inc_one;
        new_my_str->dec = &dec_one;
        new_my_str->iLen = 0;
        return new_my_str;
}

void inc_one()
{
        ((my_str*)this)->iLen++;
}

void dec_one()
{
        ((my_str*)this)->iLen--;
}

main()
{
        my_str *a = init_my_str();
        printf("a->iLen = %d\n", a->iLen);
        SEL(a)->inc();
        printf("a->iLen = %d\n", a->iLen);
}
handrake의 이미지

전웅 wrote:
lovewar wrote:
아래코드는 this란 static 변수를 제거하고, 구조체에 대한 reference를 파라미터를 사용해서 만들었습니다.

이기법은 C를 C++로 흉내낼때 사용하는 기법으로 나온것을
따라 했습니다.

...
    a->inc(a);
    b->dec(b);
...

결국은 원점으로 돌아오게 되었습니다.

handrake wrote:
그렇긴 그렇습니다만, 매크로로

#define SEL ( (this) = (a) )

물론,

#define SEL(a) (this = (a))
void *this;

를 의도하신 것이라 생각합니다.

handrake wrote:
이렇게 만들면 사용할 때 아래와 같이 매번 type-casting을 해줘야 하는 불편이 있는거 같아서요.

((my_str*)SEL(a))->inc()

혹시 해주지 않고도 사용할수 있는 방법이 있을까요?

잠시 외도를 했던 논의가 다시 정상궤도로 돌아오게 되어 기쁩니다. ;-)

제 생각에는 C 로 프로그래밍을 하면서 반드시 C++ 의 "형식"을 빌려야 할
필요를 크게 느끼지 못해 this 에 해당하는 바를 인자로 전달해 주는
방식이면 충분히 좋다고 생각합니다만, "비표준 확장"을 사용해서라도
반드시 SEL() 매크로를 사용하고 싶으시다면 다음과 같은 방법도 있긴
있습니다.

#define SEL(a) ((typeof (a)) (this = (a)))

흠... "비표준 확장"에 "전역 변수"라...

굳이 이렇게 까지 해야 되는 이유는 없지만 (파라미터를 넘기는 방법으로도 충분하니까요 ^^)
저로써는 어떻게 보면 지적유희(?)에 가까운 호기심 때문에 계속 생각을 해보게 되었습니다.

handrake의 이미지

lovewar wrote:
전웅 wrote:
lovewar wrote:
아래코드는 this란 static 변수를 제거하고, 구조체에 대한 reference를 파라미터를 사용해서 만들었습니다.

이기법은 C를 C++로 흉내낼때 사용하는 기법으로 나온것을
따라 했습니다.

...
    a->inc(a);
    b->dec(b);
...

결국은 원점으로 돌아오게 되었습니다.

위글들을 다 읽지 못했습니다 . 죄송합니다.

전웅 wrote:

코드:
#define SEL(a) ((typeof (a)) (this = (a)))

흠... "비표준 확장"에 "전역 변수"라...

쓰레드 개념이 필요할때는 다른 기법(lock-unlock)들도 같이 있어야 할것 같습니다.

쓰레드 개념까지는 미처 생각을 해보지 못하였네요. 또 다시 한번 고민을 시작해봐야 하겠습니다. :oops:

전웅의 이미지

lovewar wrote:
전웅 wrote:

코드:
#define SEL(a) ((typeof (a)) (this = (a)))

흠... "비표준 확장"에 "전역 변수"라...

쓰레드 개념이 필요할때는 다른 기법(lock-unlock)들도 같이 있어야 할것 같습니다.

저 역시 전역 변수를 사용해 this 를 구현하는 방식이 결코 바람직하다고
생각하지는 않습니다. lock-unlock 까지 고민해야 할 단계까지 왔다면 이는
구현 자체보다 다른 부분에 더 많은 비용을 들여야 한다는 사실을
암시합니다.

handrake wrote:
다시 한번 삽질해 보니 다음것이 좀 더 나은거 같습니다.

...
#define SEL(my_str_this) (((this = my_str_this)==0)?(0):(my_str_this))
...

제가 이와 같은 방식을 피하고 비표준 연산자인 typeof 를 끌어온 이유는
이 경우 SEL() 매크로가 주어진 인자를 2번 평가하기 때문입니다. 즉,
프로그램이 아닌 documentation 을 통해 SEL() 매크로의 사용 형태를
제한해야 하는 위험성을 갖습니다. 예를 들어,

SEL(get_the_class(info_arr[i++]))->method();

와 같이 실행할 경우 본의 아니게 함수가 2번 호출되고 i의 값이 2번
수정되는 결과를 낳게 됩니다. getc(), putc() 마냥 스팩에 "매크로로
구현되어 인자를 2번 이상 평가할 수도 있다"는 경고를 담는 방식은
지양해야 합니다.

또한, 그대로 강행한다고 해도 my_str_this 로 null pointer 가 오는
경우를 판별한 후에 다시 결과로 null pointer 를 반환해 null pointer
참조가 일어나게 할 필요는 없습니다. null pointer 일 경우에 대한 예외
처리를 별도로 담지 않으실 거라면 위의 구현은

#define SEL(a) (this = (a), (a))

와 다를 바 없습니다 (더구나 불필요한 비교가 없으므로 더 나을 수
있습니다).

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

handrake의 이미지

전웅 wrote:
lovewar wrote:
전웅 wrote:

코드:
#define SEL(a) ((typeof (a)) (this = (a)))

흠... "비표준 확장"에 "전역 변수"라...

쓰레드 개념이 필요할때는 다른 기법(lock-unlock)들도 같이 있어야 할것 같습니다.

저 역시 전역 변수를 사용해 this 를 구현하는 방식이 결코 바람직하다고
생각하지는 않습니다. lock-unlock 까지 고민해야 할 단계까지 왔다면 이는
구현 자체보다 다른 부분에 더 많은 비용을 들여야 한다는 사실을
암시합니다.

handrake wrote:
다시 한번 삽질해 보니 다음것이 좀 더 나은거 같습니다.

...
#define SEL(my_str_this) (((this = my_str_this)==0)?(0):(my_str_this))
...

제가 이와 같은 방식을 피하고 비표준 연산자인 typeof 를 끌어온 이유는
이 경우 SEL() 매크로가 주어진 인자를 2번 평가하기 때문입니다. 즉,
프로그램이 아닌 documentation 을 통해 SEL() 매크로의 사용 형태를
제한해야 하는 위험성을 갖습니다. 예를 들어,

SEL(get_the_class(info_arr[i++]))->method();

와 같이 실행할 경우 본의 아니게 함수가 2번 호출되고 i의 값이 2번
수정되는 결과를 낳게 됩니다. getc(), putc() 마냥 스팩에 "매크로로
구현되어 인자를 2번 이상 평가할 수도 있다"는 경고를 담는 방식은
지양해야 합니다.

또한, 그대로 강행한다고 해도 my_str_this 로 null pointer 가 오는
경우를 판별한 후에 다시 결과로 null pointer 를 반환해 null pointer
참조가 일어나게 할 필요는 없습니다. null pointer 일 경우에 대한 예외
처리를 별도로 담지 않으실 거라면 위의 구현은

#define SEL(a) (this = (a), (a))

와 다를 바 없습니다 (더구나 불필요한 비교가 없으므로 더 나을 수
있습니다).

그렇군요. 아주 많은 것을 새로 알게 된 것 같습니다. 아쉽게도, 무리하게 전역변수를 써서 OOP를
구현하려는 노력은 여기서 접어야 하겠습니다. 여러 선배님들이 인자로 넘기는 방식으로 OOP를
구현해 온게 역시 우연은 아니었나 봅니다. C의 문법이 허용하는 한도 내에서 최대한의 효율을
이끌냈던 것 같습니다.

많은 여러분들의 친절한 답변에 감사드립니다 :)

전웅의 이미지

handrake wrote:
그렇군요. 아주 많은 것을 새로 알게 된 것 같습니다. 아쉽게도, 무리하게 전역변수를 써서 OOP를
구현하려는 노력은 여기서 접어야 하겠습니다. 여러 선배님들이 인자로 넘기는 방식으로 OOP를
구현해 온게 역시 우연은 아니었나 봅니다. C의 문법이 허용하는 한도 내에서 최대한의 효율을
이끌냈던 것 같습니다.

헉, 님의 지적유희(?)가 부질없으니 이제 멈추라고 말씀드리는 것은
아니었습니다. "fun" 을 위해서는 무슨 일인든 못하겠습니까? 다만, 실제
개발 과정에서 C++ "형식"을 빌려올 때 무시 못할 한계가 있음을 말씀드린
것 뿐입니다.

여유가 되신다면 유희를 멈추지 말고 계속 이어가시길 바랍니다. 그렇게
나온 방법들이 이 문제에 한해서는 안 어울릴지 몰라도 다른 문제에는
요긴하게 사용될 수 있다고 생각합니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

irondog의 이미지

저도 몇 년 전에 같은 것을 고민을 하다가 우연히 알게 된 것이 glib/gtk였습니다.
그곳에서는 클래스를 해쉬로 구현해 놨던걸로 기억하는데 지금은 어떻게 변했나 모르겠네요.

http://gtk.org/

현재 gnome의 코어 라이브러리죠.

익명 사용자의 이미지

전웅 wrote:

흠... "비표준 확장"에 "전역 변수"라...

저도 같은 생각입니다. 역시 무리수가 있나 봅니다. 한가지 더 덧붙이자면 전역 변수로 할 경우에... 두가지 종류 이상의 클래스가 있고 한 클래스 내에 다른 클래스의 인스턴스가 멤버로 포함되어 있고 클래스의 메소드 내에서 멤버 변수로 있는 인스턴스의 메소드를 호출하는 경우에 호출까지는 괜찮지만 다시 복귀한 다음에 this의 값이 복구되지 않는 문제점이 있겠네요. 결국 호출시 원래 this를 저장했다가 복구하는 것까지 해야 될지도 모르겠네요.

pok의 이미지

irondog wrote:
템플릿 정도라면 모를까 상속을 통해 코드의 재사용성을 높인다는 말도 그래서 말이 안된다고 생각하고 있었습니다. 차라리 코드의 재사용성을 높이려면 오픈소스로 가는게 맞는 거라고 봅니다. :D

저도 흔히 이야기하는 "유도"되는 형식이 작은 아키텍쳐에도 남발되어있으면 짜증나지만, 역시 잘만들어지면 사용하기 편하죠.(MFC나, QT, 혹은 스윙 모두 잘 만들어진것 같습니다) 다만, 유도될만큼 계층적인게 실제 프로그래밍시에 별로 없다는데 동의합니다.

irondog wrote:
OOP라하면... 추상화, 다형성, 상속 요게 핵심인 것 같은데...
요거 프로그래밍 하면서 잘 적용하고 계시나요?

요즘 STL을 한창쓰면서 무척 잘 쓰고 있습니다. 컨테이너안의 객체들은 부모로부터 파생되게 하고 부모에는 인터페이스를 정의해주고 컨테이너 밖 객체에서는 그냥 부모 인터페이스만 호출해주면 자식클래스들은 알아서 자기할일 해주니... 아주 해피해피합니다. C에서 C++로 넘어갔을때보다 C++에서 STL을 배울때가 더욱 충격(?)이 크네요.

감히 이야기하자면, 컨테이너 없는 OOP는 반쪽짜리 OOP라는 생각까지 듭니다.

only2sea의 이미지

irondog wrote:
템플릿 정도라면 모를까 상속을 통해 코드의 재사용성을 높인다는 말도 그래서 말이 안된다고 생각하고 있었습니다. 차라리 코드의 재사용성을 높이려면 오픈소스로 가는게 맞는 거라고 봅니다. :D

그렇겠네요. 갖다 붙이는거 만한게 아직 없는 걸까요...
템플릿이랑 상속을 같이 써도 비교적 이쁜 모양이 되어서 기분이 좋더군요. 재사용에도 꽤 좋고...

pok wrote:

요즘 STL을 한창쓰면서 무척 잘 쓰고 있습니다. 컨테이너안의 객체들은 부모로부터 파생되게 하고 부모에는 인터페이스를 정의해주고 컨테이너 밖 객체에서는 그냥 부모 인터페이스만 호출해주면 자식클래스들은 알아서 자기할일 해주니... 아주 해피해피합니다. C에서 C++로 넘어갔을때보다 C++에서 STL을 배울때가 더욱 충격(?)이 크네요.

감히 이야기하자면, 컨테이너 없는 OOP는 반쪽짜리 OOP라는 생각까지 듭니다.

polymorphic의 마술이지요.

익명 사용자의 이미지

Anonymous wrote:
Anonymous wrote:
... 전략
OOP 가 한마디로 정의하기 어려운 아주 어렵고도 심오한-_- 개념이니 저책을 사서 봐야지만 한다는 뭐 그런류의 글인가요?
위의 책광고-_-에서 언급한 OOP 의 개념비스무리 한 것은 딱 한줄이군요.
'OOP에 관한 여러 책들에서 object란 data와 algorithm의 결합이라고 지칭하지만' <- 이부분....
그나마도 부정확하군요.

명확하지 않은 개념은 그저 도나 기에 관심있는 분들에게나 필요한 것입니다.

글 좀 똑바로 읽읍시다. 난독증인가???

Quote:
또, 이 책에서 설명하는 OOP는 Booch를 중심으로 표준화된 전통적인 SE 진영의 OOP와는 조금씩 다르게 보인다. 여러번 책에서 언급되는 Smalltalk community 쪽(이를 공식적으로는 어떻게 지칭하는지 모르겠다.)에서 발전된 생각으로 보인다. 한가지 예로, OOP에 관한 여러 책들에서 object란 data와 algorithm의 결합이라고 지칭하지만, 이 책에서는 그러한 생각을 과감하게 거부한다. object란 behavior로 정의된다고 주장한다. 이러한 생각 한가지만으로도 object design에는 엄청난 영향을 미치게된다고 생각된다. (이 주제에 대해서는 나중에 따로 다뤄보겠다.)

"책광고에서 언급한"... 언급의 의미를 모르시나봐요.
혹시 저 책 번역자? 글도 제대로 못 파악하는 자가 웬 번역이람.
국어공부 좀 제대로 받았으면 좋았을 걸...... 요즘 학생들은 너무 엉망이에요.

익명 사용자의 이미지

어떤 바보들의 행태 중 이런 것이 있습니다.

어느 책에 이런 문장이 있다고 칩시다.

'OOP 는 설명하기 어려운 개념이다'

이따위 문장을 읽고, 정말로 'OOP 는 추상적인 어떤 그 무엇이며 생명의 근원이다 어쩌구저쩌구...' 라고 믿어버리는 바보들이 실제로 있다는 것입니다.

비판적 읽기를 배우지 못한 바보들이죠. 자기 혼자 거기서 멈추면 아무 일 없을텐데, 문제는 그런 무지몽매함 마저 주위로 전파하려는 작태입니다.
그나마 그런 이유를 들어 자기의 영리를 채우려고 하는 (예를 들어 책광고) 경우는 애교로 봐줄 수도 있을 것 같습니다만, 결코 애교라고는 보고 싶지 않군요. 으하하..

참으로 어이없죠.

skyul의 이미지

『 Communcations of the ACM 』 Feburary 2006/Vol 49, No.2에 실린 ‘The Quarks of Object-Oriented Development’라는 글은 그간 OOP 개념을 설명한 논문과 자료들을 바탕으로, 사람들이 OOP를 말할 때 구체적으로 어떤 개념을 드는지 설명하고 있습니다.

저자의 조사에 따르면 상속(88%), 객체(78%), 클래스(71%), 캡슐화(63%), 메쏘드(57%), 메시지 패싱(56%), 폴리몰피즘(53%), 추상화(51%) 등이 상위권을 차지했고, 하위권에는 프레임워크(1%), 재활용(3%), 커플링(2%) 등등 비교적 덜 빈번한 OOP의 개념들이 차지하고 있더군요.

상위 8개 정도의 개념에 대해서는 이 개념이 OOP에 포함된다는 것에는 광범위한 동의가 이루어졌지만, 책이나 논문마다 구체적으로 조금씩 다르게 정의하고 있고,

그 외 하위권을 차지한 개념들은 어떤 사람들은 OOP라고 생각하는 반면에 그렇게 생각하는 사람들도 많더군요. 그리고 소프트웨어 개발 생명 주기에서, 디자인에 주안점을 주는 사람과, 구현에 주안점을 두는 사람들 사이에서도 꽤 큰차이를 보이고 있고요.

OOP에 대한 통일된 정의가 없는 게 문제겠죠.

--
서광열 소프트웨어 블로그: http://skyul.tistory.com 입니다.

handrake의 이미지

전웅 wrote:

헉, 님의 지적유희(?)가 부질없으니 이제 멈추라고 말씀드리는 것은
아니었습니다. "fun" 을 위해서는 무슨 일인든 못하겠습니까? 다만, 실제
개발 과정에서 C++ "형식"을 빌려올 때 무시 못할 한계가 있음을 말씀드린
것 뿐입니다.

여유가 되신다면 유희를 멈추지 말고 계속 이어가시길 바랍니다. 그렇게
나온 방법들이 이 문제에 한해서는 안 어울릴지 몰라도 다른 문제에는
요긴하게 사용될 수 있다고 생각합니다.

그럼 염치 불구 하고 한번 더 상상의 나래를 펴보겠습니다. 8)

비표준 연산자인 typeof를 사용하지 않으려 하니 두 가지 방법이 떠오르더군요.
첫번째는 type을 그냥 넘겨주는 법 (...) 왜인지 쉽게 가려는데 더 어려워 지는 것 같지만 그렇게 할 수 밖에 없더라고요.
두번째는 define ##를 이용해서 SEL을 각각의 타입마다 만들어 주는 다소 무식한 방법이었습니다. (사실은 웹에 그런 예제가 있더라고요)

그리고 함수를 또 불렀을 때 this를 잃어버리는 문제는 어쩔 수 없이 local this를 만들어 주었습니다.
완성되니 다음처럼 되어 있더군요... (점점 복잡해지기만 하고 쓸모는 없어지는 듯한 느낌을 지울 수가 없네요. :? )

#include<stdio.h>
#define SEL(a, type)	((type*)(gThis=(a)))

void *gThis = 0;

#define DeclareSEL(type)	\
type*	\
SEL_ ## type(type* a)	\
{	\
	gThis = (void*) a;	\
	return a;		\
}

typedef struct my_str my_str;

DeclareSEL(my_str)

void inc_one();
void dec_one();

typedef void (*void_func)(void);

struct my_str {
	int iLen;
	void_func inc;
	void_func dec;
};

my_str* init_my_str()
{
	my_str *new_my_str = (my_str*) malloc(sizeof(my_str));
	new_my_str->inc = &inc_one;
	new_my_str->dec = &dec_one;
	new_my_str->iLen = 0;
	return new_my_str;
}

void inc_one()
{
	my_str* this = (my_str*) gThis;
	this->iLen++;
}

void dec_one()
{
	my_str* this = (my_str*) gThis;
	this->iLen--;
}

main()
{
	my_str *a = init_my_str();
	printf("a->iLen = %d\n", a->iLen);
	SEL_my_str(a)->inc();			// 1
	printf("a->iLen = %d\n", a->iLen);
	SEL(a, my_str)->dec();			// 2
	printf("a->iLen = %d\n", a->iLen);
	free(a);
}

1번과 2번 중 그나마 나은 것이 어떤 것일까요. :oops:

handrake의 이미지

irondog wrote:
저도 몇 년 전에 같은 것을 고민을 하다가 우연히 알게 된 것이 glib/gtk였습니다.
그곳에서는 클래스를 해쉬로 구현해 놨던걸로 기억하는데 지금은 어떻게 변했나 모르겠네요.

http://gtk.org/

현재 gnome의 코어 라이브러리죠.

GTK 소스를 받아서 한번 들여다 보려고 했지만 너무 방대한지라 어디가 어딘지 통 알기가 힘들더군요...

대충 어딘지라도 알려주실 수 있을까요? ^^

irondog의 이미지

handrake wrote:
irondog wrote:
저도 몇 년 전에 같은 것을 고민을 하다가 우연히 알게 된 것이 glib/gtk였습니다.
그곳에서는 클래스를 해쉬로 구현해 놨던걸로 기억하는데 지금은 어떻게 변했나 모르겠네요.

http://gtk.org/

현재 gnome의 코어 라이브러리죠.

GTK 소스를 받아서 한번 들여다 보려고 했지만 너무 방대한지라 어디가 어딘지 통 알기가 힘들더군요...

대충 어딘지라도 알려주실 수 있을까요? ^^


제가 분석했던게 2001년도 가을쯤이었는데, 그새 버전업이 엄청나게 이루어졌네요. 최신 안정버전 받아서 찾아 봤는데 내용도 좀 바뀌긴 했네요. 좀더 보기 좋아진듯도 싶고... ^^;

일단 gtk2.8버전 기준으로 객체가 구현된 곳을 말씀을 드리면요.
glib-2.8.x를 받으셔서 압축을 푸시고 gobject 디렉토리를 보시면 됩니다. 그 중에 gtype.h, gobject.h, gobject.c 를 먼저 보기 시작하면 될 것 같습니다.

지금도 마찬가지인듯 싶은데 가장 바닦부터(기초가 되는 라이브러리; 해쉬, 트리, 리스트, 메모리 등등) 보시려면 glib 디렉토리부터 보시면 됩니다.

dondek의 이미지

돼지군 wrote:
완전히 알려지지 않은 구조체

C 언어로 은닉 (Encapsulation) 을 구현하는 쓸모있는 방법입니다.
비슷한 방법이 C++ 에서 재번역 의존성 제거법으로도 쓰이고요.
(Herb Sutter 님의 Exceptional C++ 참고)

List of "foo.c" :

#include "bar.h"

int main()
{
   BAR *bar = create_bar();
   use_bar(bar);
   remove_bar(bar);
   return 0;
}

List of "bar.c" :

#include "bar.h"

struct BAR_
{
  int somedata1;
  int somedata2;
  void *memory;
};
typedef struct BAR_ BAR;

BAR *create_bar() { static BAR b; return &b; }
void use_bar(BAR *) {  }
void remove_bar(BAR *) { }

List of "bar.h" :

struct BAR_;

struct BAR_ *create_bar();
void use_bar(struct BAR_ *);
void remove_bar(struct BAR_ *);

C 써본 지 하도 오래되어 잘 모르겠지만,
대충 이 정도면 충분한 것으로 알고 있습니다.
이의 제기 해주세요.

create_bar() 함수에서 static으로 만들게 되어있는데 그렇다면 이 함수를 사용해서 여러개의 BAR 객체(객체라고까지 할 건 없지만)를 만들수는 없겠네요? static 변수의 주소를 되돌리게 되어있으니 말이예요.

진리를 나의 수준으로 끌어내리지 마라.
나를 진리의 수준으로 끌어올려라. - 배꼽 중에서

페이지

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.