이타주의 프로그래머의 블로그
Posts tagged C++
뇌를 자극하는 C++
Dec 28th
6년이나 되어서 조만간 폐간되려나 생각하고 있었는데 7쇄를 인쇄하게 되었다고 한다. 경제도 어려운데 고마운 일이다 ^^
4년전에 개정판이 나온 이후로 아주 오랜만에 오탈자를 검토하느라 책을 한 번 읽어보았다. 부족한 부분이 많이 보인다. 집필 당시보다 3배 가까이 경력이 늘어났으니 그럴만도 하다. 이 부분은 이렇게 하는 것이 좋았을텐데, 라고 몇 군데 메모를 적어봤다.
그래도 최선을 다했음이 느껴진다. 병특이 끝나고 대학 4학년을 보내면서 수업시간, 숙제시간 이외에는 기숙사에 틀어박혀 글을 쓰던 생각이 난다. 마감이 항상 늦어져서 가슴 졸이던 기억이 난다. 시험 전날 새벽에 목덜미를 부여잡고 벼락치기를 하면서 가슴 졸이는 그런 느낌이다.
내가 책을 썼었는지 가끔 까먹기도 하지만, 책을 펼쳐보니 당시의 고민과 진심이 묻어나온다.
JSF C++ Coding Standards
Dec 11th
JSF Air Vehicle – C++ Coding Standards (Revision C)http://www.jsf.mil/downloads/documents/JSF_AV_C%2B%2B_Coding_Standards_Rev_C.doc
JSF의 C++ 코딩 표준 문서(doc) 다운로드
강력한 Coding Style – xper 그룹http://groups.google.com/group/xper/browse_thread/thread/22663b494244e858/38880e4db62cfe11?show_docid=38880e4db62cfe11
위의 링크를 소개해준 원문
비행기 만드는 JSF사에서 만든 엄격한 C++ 코딩 표준문서랍니다. 사람 목숨이 달린 일이니 아주 엄격하겠다는 생각이 막 듭니다.
Xper 그룹에서 알게되었구요, 관심있으신 분은 Xper 그룹도 구독해보세요. 좋은 내용이 많이 올라옵니다.
C++ 라이브러리 만들기는 어려워
Aug 24th
[옛날 블로그 글입니다. 2009.08.24]
[추가1. VC++의 예외 바이너리 호환성에 대해 내용 추가(정정)했습니다]
오랜만에 시간이 좀 나서, 요새 머리를 괴롭히는 이슈를 좀 적어 봅니다.
회사에서 C++ 라이브러리를 만들고 있습니다. 이녀석을 바이너리(dll)로 배포할 목적입니다. 컴파일러 버전별로 다 제공하기에는 무리가 있으니, 컴파일러 버전에 독립적인 바이너리가 되도록 하고 싶습니다.
이 목적을 달성하기 위해서는
- DLL에서 할당한 메모리를 EXE에서 해제하면 안됩니다.
- DLL의 인터페이스에서 STL을 쓰면 안됩니다.
- DLL에서 예외를 던지면 안됩니다.
이 규칙을 모두 만족하는 인터페이스란
- 바로 Windows API와 같은 C 함수들
- COM 인터페이스
정도가 되겠네요.
DLL에서 할당한 메모리는 DLL에서 해제
메모리를 할당해 준 CRT가 해제해야 한다는 얘기죠. 컴파일러 버전에 독립적이려면 DLL을 정적 CRT 라이브러리와 링크하는게 좋은데, 이러면 DLL과 EXE가 사용하는 CRT가 달라집니다. 그래서 DLL에서 할당한 메모리를 EXE에서 해제하면 안됩니다.
같은 컴파일러 버전으로 빌드된 DLL과 EXE이더라도 CRT가 다르면 조심해야 합니다. 같은 CRT(DLL)를 쓴다면 신경 안 써도 되구요.
그래서 DLL에서 문자열이나 메모리 블럭을 건네줄 일이 있다면, COM처럼 자기네 CRT에서 할당/해제하는 SysAlloc(), SysFree() 같은 함수를 만들어 제공하기도 합니다. DLL에서 SysAlloc()으로 메모리 블럭을 할당해서 주면 EXE에서 SysFree()로 해제하는 식이죠.
아니면 전통적인 방식으로 EXE에서 DLL에게 '메모리 블럭 크기가 몇이냐?' 물어보고 나서, EXE가 메모리를 할당해서 DLL에게 '여기에 넣어줘'라고 말하는 방법이 있습니다.
SysAlloc() 방식은 크기를 물어보는 등의 귀찮은 작업이 없는게 장점이고, 전통적인 방식은 사용자(EXE)가 자신의 메모리 풀 같은 것은 만들어 쓸 때 유리한 면이 있습니다.
DLL의 인터페이스에서 STL을 쓰면 안됨
STL의 구현이 컴파일러 버전별로 달라서 바이너리 호환성이 없는 것도 문제고, 메모리가 DLL경계를 넘어서는 경우도 있어서 안된다고 하네요.
네, 그래서 다른 언어 부럽지 않게 std::string을 반환하고 싶은 바램은 포기해야 합니다.
DLL에서 예외를 던지면 안됨
역시나 C++에 바이너리 표준이 없기 때문인데요, 예외 매커니즘을 구현하는 방식도 표준화 되어 있지 않기 때문에 컴파일러별로 다른게 현실입니다. 그래도 Visual C++이라면 같지 않을까 하는 기대감에 테스트를 해봤는데요.
VC++ 2008에서 예외를 던지는 DLL을 만듭니다. 그리고 VC++ 6.0, 2003, 2005, 2008, 2010에서 예외를 받는 EXE를 만듭니다. 결과는.. VC++ 6.0, 2003에서는 프로그램이 죽습니다. -_-;;
[추가1. 위에 테스트는 std::exception 오브젝트를 던지는 것였는데, std::exception의 구현차이 때문에 예외를 못받은 것 같습니다. 그냥 직접 만든 클래스의 포인터를 넘기니 모든 버전의 VC++에서 예외를 잘 받네요. 고민입니다. gcc도 비슷하다면 예외를 써도 되지않을까 고민중입니다.. ]
이로서 다른 언어 부럽지 않게 예외 처리를 하고 싶은 바램도 포기해야 합니다.
마무리
요즘의 언어처럼 쓰기 편한 인터페이스를 만들고 싶었는데 C++은 C++스럽게 써야만 하는 부분이 있었네요. 이래서 MS에서 닷넷 프레임웍을 만들었나 싶은 생각도 들었습니다.
참고자료
Binary-compatible C++ Interfaces, Chad Austin, 2002.02.15http://chadaustin.me/cppinterface.html
C++ 현재 함수이름 얻기
May 16th
[옛날 블로그 글입니다. 2009.05.16]
C에는 현재 함수의 이름을 알려주는 __func__라는 식별자가 미리 정의되어 있었네요. (C99) C++는 컴파일러마다 조금씩 다른데, MSVC는 __FUNCTION__이네요. 아래처럼하면 wchar_t* 버전도 쉽게 만들 수 있습니다. (yvals.h)
#define _STR2WSTR(str) L##str
#define STR2WSTR( str ) _STR2WSTR( str )
#define __FUNCTIONW__ STR2WSTR(__FUNCTION__)
MSDN보면 데코레이션된 이름을 반환하는 매크로나, 시그니처를 반환하는 매크로도 있네요. (__FUNCDNAME__, __FUNCSIG__)
http://msdn.microsoft.com/en-us/library/b0084kay.aspx
boost의 current_function.hpp를 보시면, 컴파일러별로 죄다 정의해둔 것도 있네요.
http://www.boost.org/doc/libs/1_38_0/boost/current_function.hpp
Google C++ Mocking Framework
Dec 15th
[옛날 블로그 글입니다. 2008.12.15]
Google에서 며칠전에 Mocking Framework를 공개했네요. 목 오브젝트(Mock Object)는 진짜 오브젝트와 똑같은 인터페이스를 갖는 테스트용의 가짜 오브젝트라고 할 수 있는데요, 요즘의 언어는 실행시간에 메소드를 추가하거나 하는 일이 쉬워서 C++ 개발자는 상상도 못하게 편리한 목 프레임웍이 많은 것 같습니다.
Visual C++에서 gmock 사용하기
Google 사이트에 설명이 잘되어 있어서 길게 설명드릴 건 없고요, 귀찮은 분들을 위해서 Visual C++에서의 간단한 설정 방법과 예제 소스를 보여드리려고 합니다.
gtest 준비하기
현재로서는 gtest가 필요하답니다. gtest를 설명하는 이전의 포스트를 먼저 읽어주세요.
[수정. 2009.11.7 gmock받으시면 안에 gtest가 들어있습니다. ]
gmock은 Visual C++ 8.0 SP1을 써야 한다고 하니, gtest도 VC 2005로 빌드합니다. 또 gmock은 Unicode를 사용하게 설정되어 있는 반면, gtest는 Multibyte를 사용하게 되어 있으니, 나중에 만들 테스트 프로젝트까지 함께 고려해서 통일시켜 주세요.
gmock 준비하기
아래 주소에서 받아서 적당한 곳에 압축을 풉니다.
http://code.google.com/p/googlemock/downloads/list
그 디렉토리 안에 msvc 디렉토리에 gmock.sln 파일이 있으니 Visual Studio에서 열어서 빌드합니다. 그러면 에러가 나지요. ^^;; C++ TR1에 있는 tuple이 필요하기 때문인데요. 아래 주소에서 boost를 받으면 됩니다.
http://www.boost.org/users/download/
boost의 압축을 풀면 버전번호가 붙은 디렉토리가 생기죠. D:\boost_1_37_0 이라고 하면 아래 두 디렉토리를 Visual Studio의 Include 디렉토리로 등록합니다.
- D:\boost_1_37_0
- D:\boost_1_37_0\boost\tr1\tr1
이제 다시 gmock을 빌드하면 msvc/Debug와 msvc/Release 디렉토리에 결과물이 생깁니다.
테스트 프로젝트 준비하기
Visual Studio에서 콘솔 프로젝트를 하나 만드세요. 우선 유니코드 설정을 gtest, gmock에 맞춰주시고, gtest, gmock은 Multithread Dll을 사용하고 있으니 CRT 설정도 잘 맞춰주세요.
지난 번 포스트를 참고해서 gtest 관련 설정을 먼저 해주시고, gmock에 대한 디렉토리 설정을 합니다.
- gmock 소스 코드 안에 include디렉토리를 추가하셔야 되고
- gmock 소스 코드 안에 msvc/Debug/gmock.lib, msvc/Debug/gmock.lib를 라이브러리로 추가하시면 끝 (참고로 Debug, Release 버전 모두 이름이 gmock.lib니까 주의하세요)
기본 골격코드는 아래와 같습니다.
#include <gtest/gtest.h>
#include <gmock/gmock.h>
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
여기까지 실행해보시고, 에러 나면 잘 잡으세요. ㅎㅎ
테스트 코드 작성하기
여러가지 다양한 기능에 대해서는 Google 문서를 봐주세요.
http://code.google.com/p/googlemock/wiki/ForDummies
아래는 테스트용 MockModel 클래스를 사용해서 Controller 클래스를 테스트하는 예제입니다.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using testing::AtLeast;
using testing::Return;
class IModel {
public:
virtual int method1() = 0;
};
class Controller {
public:
Controller(IModel* m) : model(m) {}
int OnCommand1() {
return model->method1() + model->method1();
}
private:
IModel* model;
};
class MockModel : public IModel {
public:
MOCK_METHOD0(method1, int());
};
TEST(ControllerTest, Command1) {
MockModel model;
EXPECT_CALL( model, method1())
.Times(AtLeast(2))
.WillOnce(Return(100))
.WillOnce(Return(200));
Controller controller(&model);
ASSERT_EQ( 300, controller.OnCommand1() );
}
EXPECT_CALL 부분을 보시면 목 오브젝트를 사용하고 있습니다. 말로 풀어보자면 “model객체의 method1메소드는
말이야, 적어도 2번 호출되야 하고, 처음에는 100을 그 다음에는 200을 반환하게 해줘” 정도가 되겠죠. 2번 미만으로
호출되면 테스트가 실패합니다. 또 목 오브젝트의 반환값을 정할 수 있으니 ASSERT_EQ에 보이는 것처럼 테스트하기가
쉬어집니다.
IModel은 메소드가 1개 뿐이지만, 메소드가 많은 경우라면 MockModel 클래스를 코딩하는게 귀찮은 일이죠. 그래서 코드를 자동으로 생성하는 스크립트도 있다고 하니 Google 문서를 읽어보세요.
위 코드의 결과는 이렇습니다.
마무리
Ruby나 Java 진영의 동적인 목 프레임웍을 보면서 많이 부러워했었는데요. Google에서 마법을 부리지 않고 C++스러운 프레임웍을 편리하게 만들어준 것을 보니, 아직 배울게 많다는 생각이 듭니다. 여러분도 gtest와 gmock으로 즐거운 테스팅 생활 하세요~ ^^
Google C++ Testing Framework
Dec 15th
[옛날 블로그 글입니다.2008.12.15]
올해 중순에 Google에서 C++용 테스트 프레임웍을 발표했었네요. 충분히 써보지는 못했지만, 매뉴얼 읽어보고 예제를 만들어본 소감으로는 C++용 테스트 프레임웍 중에서는 최고일 것 같습니다.
전통적인 CppUnit에 비해서 사용법이 상당이 간단합니다. 스크립트 언어를 통해서 테스트 작성을 쉽게 해주는 CxxTest에 비해서도 불편함이 없습니다. 오히려 CxxTest는 개발환경 설정하려면 make파일도 손대야해서 윈도우즈 개발자에게는 대략 난감했었구요.
또 다음 포스팅에서 설명드리려는 Google C++ Mocking Framework까지 함께 사용하면 C++ 개발자도 프레임웍 때문에 유닛테스트 만들기 힘들다는 말은 못하겠네요 -_-;;
Visual C++에서 gtest 사용하기
Google 문서가 워낙 잘 되어 있어서, 설명할 것은 많이 없고요. 귀찮으신 분들을 위해서 간단한 설정과 예제 소스 보여드리려고 합니다.
gtest 준비하기
아래 주소에서 소스 코드를 다운로드 받으시고, 압축 풀어서 적당한 곳에 둡니다.
http://code.google.com/p/googletest/downloads/list
그 안에 보시면 msvc 디렉토리가 있고, 그 안에 gtest.sln 파일을 Visual Studio에서 열어서 빌드하세요. ( 참고로 VC 7.1용 솔루션 파일입니다. ) 빌드가 끝나면 msvc/Debug, msvc/Release 디렉토리에 결과물이 생깁니다.
일단 준비는 여기까지 끝!
테스트 프로젝트 준비하기
Visual Studio에서 콘솔 어플리케이션 하나 만드시고, gtest에 대한 디렉토리 설정을 합니다.
- gtest 소스 코드 안에 include 디렉토리를 추가하셔야 되고
- gtest 소스 코드 안에 msvc/Debug/gtestd.lib, msvc/Release/gtest.lib를 라이브러리로 추가하시면 끝.
기본적인 골격코드는 아래와 같습니다.
#include <gtest/gtest.h>
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
여기까지만 실행해보셔도 좋습니다. 에러 나면 잘 잡으시구요 ㅎㅎ
테스트 코드 작성하기
테스트 코드를 그루핑하는 방법이나 다양한 Assert/Expect 방식에 대해서는 Google 문서를 봐주세요.
http://code.google.com/p/googletest/wiki/GoogleTestPrimer
아래는 간단한 예제와 그 결과입니다.
class StringTest : public testing::Test {
protected:
virtual void SetUp() {
s1 = “Muscly”;
s2 = “Blog”;
}
std::string s1;
std::string s2;
};
TEST_F(StringTest, Equal) {
ASSERT_EQ( s1, s2 );
}
TEST(VectorTest, Size) {
std::vector<int> v;
ASSERT_EQ(0, (int)v.size());
}
마무리
그동안 C++ 개발자는 Java나 C# 개발자에 비해서 손해를 봐왔다는 생각이 듭니다. 최신 개발 기법의 혜택을 보는 것은 Java 진영이 먼저였고, 닷넷 진영은 손쉽게 따라할 수 있었지만, C++ 진영은 언어의 한계로 쉽게 따라 할 수 없었죠. Microsoft도 닷넷에 힘쓰고 있는 상황에 Google이 C++ 개발자를 신경써주니 눈물이 납니다. ^^;;
C++ 개발을 하는 회사라면 표준 프레임웍으로서 권장하고 싶습니다. gtest로 즐거운 테스팅 되세요~ ^^



Recent Comments