C/C++을 섞어 쓴 경험을 얘기 해 봅시다.

pynoos의 이미지

다른 주제( http://bbs.kldp.org/viewtopic.php?t=27257 )에서는 장황하게 나오는 감이 있어서, 따로 떼어 생각해보고 싶습니다.
부디 여기에서는 섞어쓴 경험 있는 얘기만 나왔으면 하며, 이론만 늘어 놓지 않았으면 합니다.

저의 경우 C/C++이 공존하는 Unix 기반 서버 프로그램을 개발하고 있습니다.

저도 정리하고자 이렇게 수기(?)를 작성해보는 것도 좋다 생각하여 주제를 개설하였습니다.

문제점들...

* 배포상의 문제, libstdc++ 이 기본 설치 library가 아니므로(Solaris 등에서) 배포를 같이 해야하는 문제가 있습니다.
* member function 에 c 함수명, connect, accept 등을 썼다가 solaris에서 connect 가 define 문으로 되어 있는 경우가 있다보니, member 함수 이름이 바뀐 경우가 있습니다.
* C, C++이 공존하여 archive 로 될때, linux에서 특정 standard(XPG..) 를 따르면 stat 함수가 inline으로 선언되고, 따라서 weak symbol로 c++ object에 들어간 일이 있었습니다.
이 경우 순수한 C 코드인데 도 불구하고, 위 archive를 link 할 경우 C++ object에서 weak symbol을 link 시도하고 결국 사용하지 않는 libstdc++까지 dependency가 걸리더군요.

제 결론은, C 가 상위 module로 서 C++로 만들어진 library를 호출하는 구조는 경험상 좋지 않다입니다.
권하는 것은 C main에서는 하부에 C 코드만 있는 것이 생각하기 귀찮지 않더군요.

처음에는 C++ library를 C가 사용했다가.. 나중에 완전히 dup된 C 라이브러리를 만들었습니다. 주로 config, log library 입니다.

또, solaris 어떤 C library의 경우 struct type으로 queue 를 선언하는게 있었습니다. 이거 stl과 같이 쓰려니 쥐약이더군요. 결국 그 헤더 앞뒤로 queue를 define하여 다른 type으로 선언되도록 꽁수를 도입하였습니다. 이건 C/C++섞는 문제와는 다른 것이더군요.

좋은 것? 은 물론 STL, 이나 Virtual function 들.. 귀찮은 C application 에서 해방되는 것이죠...

anfl의 이미지

좀 오래전에 제가 짠 소스를 최근에 훓어 보았는데 한마디로 가관이네요.
파일명은 *.cpp인데 코딩한 방식은 전부 C를 사용하였더군요.

왜그랬을까.. 하고 생각을 해보니 당시에 C++도 제대로 모르던 상황에서 코딩을 하던 시절에 기능은 똑 같지만 인터페이스를 GUI와 CLI를 동시에 채용하고자 하였습니다.

내부 엔진을 C로 만들고 나서 GUI를 만들기 위해서 선택한것이 QT였고 어찌 어찌하여 각고의 삽질 끝에 인터페이스를 만들어 내었는데 이걸 QT에 접목을 시킬려고 하니깐 문제가 발생했었습니다.

엔진에서 GUI로 결과를 출력시켜 주어야 하는데 당시의 실력으로 정말 난감하더군요.
qprocess를 사용하여 표준 출력을 넘겨주는 형식을 취할까 했는데 이건 또 실시간성이 떨어지더군요.

그래서 잔머리 굴린 결론이 C로 짠 엔진을 C++로 바꾸어 버리는거였습니다. 헐~

돼긴 잘 돼서 프로젝트는 무사히 마무리 되었는데 왠지 뒤통수가 근질 근질 하였었다는.... 뭔가 화장실에서 일을 보는데 화장실 문에 열쇠가 고장나서 화장실 문을 손으로 붙잡고 일을 보는듯한....


kuma의 이미지

통신 프로그램은 C 스타일로 작성을 합니다.

처음 C++ 답게 작성한답시고 TCP/IP 나 RS-232C 를 작성했다가 도리어 곤욕을 치루었습니다.

이부분은 도리어 C 스타일이 더 간결하고 쉽더군요.

UI 부분은 C++ 이 아주 좋습니다.
지저분하게 핸들이나 DC 등 기타 Data 가 따로국밥으로 놀지 않아서 깔끔해 보이고 생각 또한 객체적으로 아주 잘 생각되어 지더군요. 만일 처음 C++ 를 접하시는 분이라면 X Lib 를 이용한 Class Library 구축이나 UI 를 작성 해보라고 권하고 싶을 정도입니다.

내부 Data 처리부분은 아직도 만족스럽지는 않지만 C 와 C++ 을 혼합해서 하는게 가장 편하고 좋은것 같습니다. 처음 전체를 객체로 보고 작성을 하다가 완전히 굳혀지지 않은 구조로 인해서 객체지향을 포기할뻔 한적도 있지만요. :D
그 일로 배운건 C++ 로 가능한 단위의 최소화 객체를 만들고, C 스타일의 프로그램이 배경이 돌아가는 방식을 주로 즐겨 씁니다. 여기서 상속은 어떻게 보면 보약처럼 느껴지지만 어떤 경우에는 정말 치명적이더군요.

girneter의 이미지

저는 MIPS CPU 기반의 리눅스 셋탑박스를 만들고 있습니다.

임베디드라고는 해도 PC 못지 않은 성능을 갖고 있고
C++ 크로스컴파일도 잘 되네요.

울 소프트웨어 파트가 한 7~8 명 되는데
저만 C++ 을 사용하고 다른 사람은 다들 C 를 사용합니다.
C++ 이 좋다고 이야기를 해줘도 걍 C 로 하더군요.

name mangling 때문에 interface 만 extern "C" 에 묶어두고
제가 작성중인 모듈에는 상속이며 오버로딩에
STL 까지 멋대로 쓰고 있습니다.
게다가 제가 작성하고 있는 모듈이 다른 프로젝트의 일부 결과물을
가져다 쓰고 있는데 이게 C++ 로 작성된 터라
만약 저도 C 로 개발해야 한다면
혀 깨물고 배째라 하겠다고 했죠 ^^

분명 저도 돌팔이 C++ 프로그래머라
C style 의 엉터리 C++ 프로그램을 짜고 있는거겠지만
다른걸 다 떠나서 STL 은 역시 정말 좋습니다...

개념없는 초딩들은 좋은 말로 할때 DC나 웃대가서 놀아라. 응?

saxboy의 이미지

문득 떠오르는 몇가지 기억

- 몇몇 플랫폼 (Solaris8과 hp-ux 10 이던가...) 에서 링킹하면서 explicit하게 -lC 를 붙여줘야 했던 기억

- 몇몇 플랫폼(기억 가물가물..) 에서 C++ 컴파일러가 없는데 어드민은 설치도 할 줄 모르고 설치하려면 무슨 어쩌고 저쩌고로 허락을 받아야 한다고 해서 그자리에서 모듈 몇개 C로 새로 만든 기억

- g++ 이 없었는데, header에 implementation 을 해놓은 것을 제대로 컴파일을 하지 못해 전부 implementation을 cpp 로 옮기는 닭질을 해야 했던 기억

- 모듈 몇개는 C++이고 몇개는 C여서 링킹하려고 extern "C"를 넣은 인터페이스 헤더를 몇개 새로 써준 더러운 기억

- 컴파일러는 gcc, g++, 플랫폼용으로 돈주고 산 cc 가 공존하고 있는데 패스가 제대로 맞지 않아서 라이브러리 링킹부터 온갖것이 엉망으로 되어 컴파일하자마자 seg fault 를 만난 기억

- c++로 된 so를 c로 된 메인 프로그램에서 dlopen 해야 하는데, 제대로 되지 않아서 한참 골머리를 앓다가 so 디펜던시를 찾아서 c모듈에(!) 링킹시키고 dlopen 되는걸 보았던 황당한 기억

- 이렇게 몇군데에서 c/c++/java+jni 를 섞어서 쓴데에 심하고 당하고 나서 c++에 template대신 c에 void * 를 쓰도록 팀원들을 무조건 설득한 기억. 저는 누군가 특별히 c++을 요구하거나 vc++에서 코딩할때가 아니면 요즘에는 절대 c++로 코딩하지 않는 습관이 들어버렸습니다. gtk 스타일 OO에 몰표요!

좋은 기억은 별로 없네요. 리눅스만이라면 좋았을텐데, 플랫폼 대여섯가지가 섞여 있는 기억들이라서 어디가 어디였는지 기억도 나지 않는데다가 사실은 기억해보고 싶지도 않습니다. ㅡ.ㅡ

markboy의 이미지

윈도우에서 작업할때 COM 을 제외하면 DLL을 작성할 경우 interface를 C로 하는 것이 좋습니다. (class 자체를 interface로 쓸 경우 귀찮은 문제가 생기죠. 해당 DLL을 동적으로 로드 하거나, class 자체의 멤버에 변경이 있을경우라던가). 그래서 DLL 내부 구조를 C++ 로 작성한 다음 C 로 감싸는 경우들이... :(

mastercho의 이미지

saxboy wrote:
- 몇몇 플랫폼(기억 가물가물..) 에서 C++ 컴파일러가 없는데 어드민은 설치도 할 줄 모르고 설치하려면 무슨 어쩌고 저쩌고로 허락을 받아야 한다고 해서 그자리에서 모듈 몇개 C로 새로 만든 기억

g++도 못까는 사람이 어드민하고 있다니..... 헐....

차라리 g++ 설치하는 방법을 연구하는게 낫지 않았을까 싶네요

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

markboy의 이미지

mastercho wrote:
g++도 못까는 사람이 어드민하고 있다니..... 헐....

차라리 g++ 설치하는 방법을 연구하는게 낫지 않았을까 싶네요

정석은 C++ 컴파일러 설치겠지만 실제 필드에서는 의외로 이런 것들이 발목을 많이 잡습니다. 심지어 GCC 도 안깔아 주는 경우도(그 덕에 HP-UX 에서 고생한 기억이 있습니다. :( ) 있었습니다.

윈도우 버그때문에(정확하게는 exchange server 버그였죠) hotfix 를 설치해 주어야 하는 경우에도 그쪽 관리자를 설득하기 어려운 경우도 많았고요.

최병현의 이미지

markboy wrote:
정석은 C++ 컴파일러 설치겠지만 실제 필드에서는 의외로 이런 것들이 발목을 많이 잡습니다. 심지어 GCC 도 안깔아 주는 경우도(그 덕에 HP-UX 에서 고생한 기억이 있습니다. :( ) 있었습니다.

Sparc 머신을 한 4년 관리한 적이 있는 데 첨에 컴파일이 안돼서 깜짝 놀랐습니다. 알고보니 cc가 없어서... 쩝 그거 돈주고 사야 된다고 하길래 인터넷을 한참 뒤지고 다닌 후 gcc를 구해서 설치했다는... :?

To be a rich

kihlle의 이미지

윗분들도 제가 겪은 고초(?)를 다 겪으셨군요... ㅎㅎ

- 언젠가 C++ 로 작성된 데이터베이스 라이브러리를 사용해서 C 에서 제어하도록 만들어야할 필요가 있었습니다. 클래스를 void* 로 넘겨주는 C++ 함수를 만들어서 그걸 extern "C" 로 받고... 포인터로 위치찾아서 멤버변수값 억세스하기도 하고... (멤버함수 호출은... ㅡ.ㅡ;;) 언젠가 ATL관련 사이트에서 찾아본 문서가 도움이 되서 다행히 세그먼트폴트없이 돌리긴 했지만 찝찝한 삽질을 한 경험이 있는데,... 여기서 제가 얻은 개인적인 결론은
---- 이때 C코딩을 최대한 C++에 맞추는 것이 편하다.
---- 경우에 따라서는 클래스의 동작과 C를 연결하는 브릿지(?)가 되는 C++모듈을 따로 만들어야 할 때도 있다.
---- effeciency 위주의 코딩에서 O(n)에 해당하는 핵심부에 C++ 모듈의 클래스를 제어한다든가 할때는 과감히 객체지향을 버리고 꽁수를 쓰면 극적인 성능향상을 도모할수있다.
허접한 경험에 의한 결론일 뿐이니 너무 과신하지 마시기 바랍니다. :)

- so의 디펜던시를 찾아서 모두 링크해야 런타임로딩이 되는경우는 모듈 생성당시의 라이브러리에 따라서도 (libc나 기타 라이브러리의 구버젼을 모두 갖고있어야하는 경우) 혹은 플랫폼에 따라서도 문제가 됩니다. (예를 들면 HP에서도 64비트 pa20환경이면 특정 환경변수로 해당라이브러리의 경로를 모두 지정해야 shl_load()가 작동합니다.)

- stat 함수가 __inline__ 로 선언되서 문제가 되는건 비단 C/C++ 에서의 문제만이 아닌것 같더군요. 오라클처럼 .o 형태의 오브젝트를 갖고다니다 설치시에 링크하는 보통의 대형패키지들은 libc 문제때문에 항상 문제가 되지않는가 싶습니다. 전 따로 int stat(... ) 를 정의한 헤더파일을 만들어서 같이 넣고 돌려서 해결하긴 했습니다만.

- :) :) :) :) 가장 주의해야 할것은 gcc 가 아닌 환경이라면 // 주석을 쓰지 말고 /* */ 를 쓰는 것입니다. 자꾸 사소한데서 걸리면 열받아서 일진이 안좋고 프로젝트가 전체가 안좋거든요. :) :) :) :)

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

사족으로..
외부에 용역나갔을때 대개의 경우 해당사이트에 개발툴이 제대로 설치되어있지않고, 설치해주기가 까다로울 겁니다. 개발툴들의 변종버젼들이 다양해서 옵션이 먹지않는다든가 (HPUX), 라이센스가 다되서 동작안한다든가 (SunWspro), 라이센스문제로 컴파일시간이 세월이라든가 (xlc) 그런 문제들이 단시간에 해결되지도 않거니와, gcc같은걸 새로 설치하려면 root가 시스템을 대거 갈아엎는 경우도 생기거든요. (예전에 AIX에서 아무생각없이 루트창에서 pkgadd gcc 했다가 동작안하는 경우를 봤지요. ㅎㅎ)

IDC에 들어간 웹서버 정도라면 몰라도, 적어도 제가 돌아다닌 수십개의 금융권서버에서 gcc 설치해주는 관리자는 한명도 보지못했습니다. 그게 제대로 된 관행이라고 생각되지는 않습니다만 현실입니다.

homeless

길손의 이미지

오래된 글이긴 하지만,

엄밀히 따지면 운영 중인 메인 서버에서 컴파일을 돌리고 개발을 한다는게 말이 안되는거죠.

원칙대로라면 서비스 개시 전이라면 개발 후에 컴파일러 등의 개발툴을 삭제하고 나서 운영 시작하거나, 메인서버가 이미 동작중이라면 개발서버나 백업서버쪽에서 컴파일해서 가져다 실행시켜야하겠죠. 하지만, 현실적으로 그게 가능한 환경이 거의 없다는게 문제 --;

제가 중요한 서비스가 돌아가는 유닉스 계열 서버관리자라면 저 역시 보안상의 이유로 컴파일러는 설치하지 않을겁니다. 그리고 메인 서버에서 컴파일이 필요한 상황이라면 일단 서버를 망에서 끊고, 컴파일러 설치해서 개발 작업하고, 작동 테스트하고, 컴파일러 제거하고 서비스 재개하는 과정을 거칠 겁니다.

이 과정에서 전산실 소장이 깐깐한 사람이라면,

작업 계획 보고
서비스 중단 사유서
어플리케이션 추가 보고
개발 작업 보고
테스트 계획
원복 대책
작업 완료 보고

등등이 필요할겁니다. 이것도 순조롭게 진행될 경우고, 문제발생시에는.....--;

개발자입장에서는 gcc 하나 까는게 대단할 일이 아닐지 몰라도,
관리자 입장에서는 간단한 일이 아닐 수도 있습니다.

물론, 말씀하신대로 gcc 까는 방법을 몰라서 그런 경우도 많겠지만 말입니다 ㅋㅋㅋ

espereto의 이미지

Quote:
- 가장 주의해야 할것은 gcc 가 아닌 환경이라면 // 주석을 쓰지 말고 /* */ 를 쓰는 것입니다. 자꾸 사소한데서 걸리면 열받아서 일진이 안좋고 프로젝 트가 전체가 안좋거든요.

정말... // 잔뜩 있는 코드 /* */로 고치다보면...... :evil:

VC++에서 개발된 거 유닉스용으로 포팅하다보면, 가장 짜증나는 게 주석이더군요. 나머진 어차피 ANSI C 함수들만 써서 별 문제를 안 겪었는데... // 이걸 /* */로 바꾸느라 엄청 삽질한 경험이 많습니다.

jongwooh의 이미지

라인 단위로 읽어서 처음이 //로 시작하면 그걸 /* (내용) */ 으로 바꿔주는 스크립트를 짠 다음 그 스트립트를 소스 파일들에 대해 모두 돌려주면 되지 않습니까?

스크립트를 짜는 것이 싫은 경우엔 sed 만으로도 그런 작업을 할 수 있을텐데.

espereto wrote:
Quote:
- 가장 주의해야 할것은 gcc 가 아닌 환경이라면 // 주석을 쓰지 말고 /* */ 를 쓰는 것입니다. 자꾸 사소한데서 걸리면 열받아서 일진이 안좋고 프로젝 트가 전체가 안좋거든요.

정말... // 잔뜩 있는 코드 /* */로 고치다보면...... :evil:

VC++에서 개발된 거 유닉스용으로 포팅하다보면, 가장 짜증나는 게 주석이더군요. 나머진 어차피 ANSI C 함수들만 써서 별 문제를 안 겪었는데... // 이걸 /* */로 바꾸느라 엄청 삽질한 경험이 많습니다.

you must know the power of dark side.

espereto의 이미지

Quote:
라인 단위로 읽어서 처음이 //로 시작하면 그걸 /* (내용) */ 으로 바꿔주는 스크립트를 짠 다음 그 스트립트를 소스 파일들에 대해 모두 돌려주면 되지 않습니까?

스크립트를 짜는 것이 싫은 경우엔 sed 만으로도 그런 작업을 할 수 있을텐데.


저두 그러고 싶었습니다만, 당시에는 유닉스/리눅스에서는 그저 컴파일하고 실행시켜서 테스트하는 정도 밖에 모르던 상태였답니다. ㅜ.ㅜ
아직도 리눅스/유닉스는 익숙하지 못하네요.
saxboy의 이미지

Quote:

라인 단위로 읽어서 처음이 //로 시작하면 그걸 /* (내용) */ 으로 바꿔주는 스크립트를 짠 다음 그 스트립트를 소스 파일들에 대해 모두 돌려주면 되지 않습니까?

스크립트를 짜는 것이 싫은 경우엔 sed 만으로도 그런 작업을 할 수 있을텐데.

흐... 상황에 따라 다르지요. 가끔씩은 스크립팅하느라 고생하는 것보다 그저 손으로 고치는 것이 빠른 경우도 많답니다. 스크립팅의 파워를 알면서 만나는 딜레마의 하나이지요. 그냥 노가다가 더 빠르면 스크립트를 짜지 않고 노가다로 하는 것이 낫습니다. :-)

cppig1995의 이미지

C언어의 최신 표준인 ISO/IEC 9899:1999(일명 C99)에 의하면, //를 C에서도 사용할 수 있습니다.

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