레이블이 C/CPP인 게시물을 표시합니다. 모든 게시물 표시
레이블이 C/CPP인 게시물을 표시합니다. 모든 게시물 표시

vscode clang-format style

# vscode c++ 포맷 스타일은 기본적으로 clang-format 을 사용한다.
# 포맷 스타일은 변경 예시
// linux 에선 clang 설치해야 다음을 사용할 수 있다.
"C_Cpp.clang_format_path": "/usr/local/bin/clang-format",
// .clang-format 파일이 있다면 이 설정에 따른 포맷팅
"C_Cpp.clang_format_style": "file",
// clang-format --style="google" aaa.cpp 로 사용
// .clang-format 파일이 없다면 사용할 포맷 스타일 디폴트 "Visual Studio"
"C_Cpp.clang_format_fallbackStyle": "visual studio",
// "C_Cpp.clang_format_fallbackStyle": "google",
// "C_Cpp.clang_format_fallbackStyle": "webkit",
// "C_Cpp.clang_format_fallbackStyle": "mozilla",

# 포맷 스타일 결과 비교, main 함수만 발췌
# 개인적으로 visualstudio 또는 google 스타일이 좋은것 같다.

# Visual Studio 는 Clang-format 기본스타일 종류에는 없고 다음과 같이 설정해야한다.
# clang-format --style="{UseTab: Never,IndentWidth: 4,
BreakBeforeBraces: Allman,
AllowShortIfStatementsOnASingleLine: false,
IndentCaseLabels: false,
ColumnLimit: 0}" hello_world.cpp
# 참고로 -i 옵션을 주면 변경된 스타일이 파일에 적용된다.
# 들여쓰기 탭, 시작 중괄호 한줄 차지
int main()
{
    string a = "1";
    if (a == "1")
    {
        cout << "hello world" << endl;
    }
    return 0;
}

# clang-format --style="google" hello_world.cpp
# 들여쓰기 공백2, 시작 중괄호 같은 라인에 시작
int main() {
  string a = "1";
  if (a == "1") {
    cout << "hello world" << endl;
  }
  return 0;
}

# clang-format --style="webkit" hello_world.cpp
# 들여쓰기 공백4, 함수 시작 중괄호만 한줄, 함수내에서는 같은 라인에 시작
int main()
{
    string a = "1";
    if (a == "1") {
        cout << "hello world" << endl;
    }
    return 0;
}

# clang-format --style="mozilla" hello_world.cpp
# 들여쓰기 공백2, 함수 시작 중괄호만 한줄, 함수내에서는 같은 라인에 시작
# 함수 리턴 타임 한줄 차지
int
main()
{
  string a = "1";
  if (a == "1") {
    cout << "hello world" << endl;
  }
  return 0;
}

g++ warning missing initializer for member

다음과 같이 time struct(tm) 생성시 초기화를 하지 않은 상태의 c++코드가 있을때

#include <iostream>
#include <sys/time.h>
int main() {
    struct tm aaa{};
    std::cout << aaa.tm_sec << std::endl;
    return 0;
}

다음과 같이 빌드 하면 괜찮은데,
g++ -std=c++11 ysoftman.cpp
또는
g++ -std=c++11 -Wall ysoftman.cpp

다음과 같이 -Wextra 옵션을 주면�warning 이 발생한다.
g++ -std=c++11 -Wextra ysoftman.cpp

ysoftman.cpp:5:16: warning: missing initializer for member ‘tm::tm_sec’ [-Wmissing-field-initializers]
  struct tm aaa{};
                ^
ysoftman.cpp:5:16: warning: missing initializer for member ‘tm::tm_min’ [-Wmissing-field-initializers]
ysoftman.cpp:5:16: warning: missing initializer for member ‘tm::tm_hour’ [-Wmissing-field-initializers]
...

참고로 -Wextra 는 -Wall 에 포함되지 않는 warning 에 대한것으로
위와 같이 초기화 누락이나 포인터를 정수형과 비교할때 발생하는 경고(comparison between pointer and integer) 를 활성화 한다.
그리고 -W 옵션 대신 -Wextra 를 사용하라고 한다.
g++ -v --help | grep Wextra
-W switch is deprecated; use -Wextra instead

[해결방법1]
-Wextra 를 사용하지 않기
찾아보니 사실 기본 0값으로 초기화되는데 gcc 는 너무 과도하게 warning 을 발생한다는 의견도 있다.

[해결방법2]
다음과 같이 모든 멤버를 초기화한다. (struct 내의 생성자()를 두고 초기화하면 편한데, tm 은 standard library라 그럴 수 없다.)
    struct tm aaa{
    .tm_sec=0,
    .tm_min=0,
    .tm_hour=0,
    .tm_mday=0,
    .tm_mon=0,
    .tm_year=0,
    .tm_wday=0,
    .tm_yday=0,
    .tm_isdst=0,
    .tm_gmtoff=0,
    .tm_zone=NULL};

[해결방법3]
경고 메시지대로 -Wno-missing-field-initializers 를 추가해서 초기화 경고만 제외시킨다.
g++ -std=c++11 -Wextra -Wno-missing-field-initializers ysoftman.cpp

vscode c++ template angle bracket error

# c++ 사용중 다음과 같이 중첩 template 사용시 >(angle bracket)이 연속으로 붙어 있는 경우
vector<vector<int>>

# mac에서 vscode problems 창에 다음과 같은 에러메시지가 나오고 있다.
a space is required between consecutive right angle brackets (use '> >')

# template 연속 angle bracket 에러는 c++11 에서 수정돼 컴파일시 문제가 없다.
# vscode 설정에서 다음과 같이 또는 c++14, c++17 등 상위버전을 설정했지만 계속 에러메시지가 보인다.
"C_Cpp.default.cppStandard": "c++11",

# 이밖에도 c++11 의 auto type 사용할 수 없다는 다음의 에러가 발생한다.
'auto' type specifier is a C++11 extension [-Wc++11-extensions]

# 해결방법
# vscode > open settings (JSON) > 에서 다음과 같이 clang 컴파일러의 -std=c++11 을 명시하면 된다.
"clang.cxxflags": [
    "-std=c++11"
]

user request scheme in apache httpd module

# apache httpd 에 사용 할 C/C++ 모듈 예)mod_ysoftman.so 개발시
# ap_hook_handler 를 통해 request_rec* req (사용자 요청 레코드)를 받을 수 있다.
# scheme(http, ftp,..) 종류를 파악해보자
# httpd.h 에 명시된 매크로 사용 하면 된다.(v2.2 이상)
ap_run_http_scheme(req)

# 그런데 gtest 빌드시 다음 에러가 발생한다.
undefined reference to `ap_run_http_scheme'

# gtest 컴파일은 -lapreq2 -lapr-1 라이브러리만 링크하게 되는데
# ap_run_http_scheme 와 같이 ap_ 로 시작하는 함수들은
# httpd daemon 루틴으로 httpd 데몬 실행 환경에서만 사용할 수 있다.
# 다음 exp 파일에서 각각 라이브러리에서 사용하는 함수들을 확인할 수 있다.
apache/modules/httpd.exp
apache/lib/apr.exp, aprutil.exp

# httpd library 를 -l 링크하지 않으면 ap_xxx 함수들을 찾을 수 없게 된다.

##########

# 삽질~
# ap_xx 대신 apr(apache runtime) 라이브러리에서 비슷한 함수을 찾아 봤다.
# apr 라이브러리에서는 apr_uri_parse() 로 scheme 를 알 수 있다.
# 하지만 req->uri, unparsed_uri,.. 등을 찍어보면 scheme 정보가 없다.
fprintf(stderr, "ysoftman unparsed_uri %s\n", req->unparsed_uri);
fprintf(stderr, "ysoftman uri %s\n", req->uri);
fprintf(stderr, "ysoftman the_request %s\n", req->the_request);
fprintf(stderr, "ysoftman path_info %s\n", req->path_info);
fprintf(stderr, "ysoftman args %s\n", req->args);
fprintf(stderr, "ysoftman protocol %s\n", req->protocol);
fprintf(stderr, "ysoftman method %s\n", req->method);
fprintf(stderr, "ysoftman content_type %s\n", req->content_type);
fprintf(stderr, "ysoftman user %s\n", req->user);
fprintf(stderr, "ysoftman ap_auth_type %s\n", req->ap_auth_type);

# 따라서 다음과 같이 req->pool 에서 찾는게 아니라 scheme 이 포함된 url 스트링을 주고 이를 파싱하는데만 쓸 수 있다.
apr_uri_t parsed_uri;
apr_status_t ret = apr_uri_parse(req->pool, "http://ysoftman.com", &parsed_uri);
if (ret != APR_SUCCESS)
{
    return "";
}
fprintf(stderr, "ysoftman parsed_uri.scheme %s\n", parsed_uri.scheme);

##########

# 해결방법 - gtest 에서 ap_run_http_scheme 을 찾지 않도록 자체 구현하면 된다.
# gtest 코드에서 다음과 mockup 함수로 선언하고
# MOCK_CONST_METHOD + 파라미터 개수 + (함수명, 리턴타입())
MOCK_CONST_METHOD0(scheme, std::string());

# cpp 파일에 C 스타일로 컴파일도록하고
# 의미없는 ap_run_http_scheme() 를 구현해놓는다.
#ifdef __cplusplus
extern "C" {
#endif
char *ap_run_http_scheme(request_rec *r)
{
    return NULL;
}

#ifdef __cplusplus
}
#endif

C++ vector naming?

c++ STL(Standard Template Library) 에서 많이 사용하는 vector 의 이름은 STL 을 Alex's lesson 가 기존 C 에 내장된 배열(array)과 구분하기 위해 선택한것이라고 한다. 그런데 수학에서 고정된 숫자 순서를 vector 라는 용어로 사용한다고 하니 동적길이를 가지는 C++ STL 을 생각하면 혼동이 될것 같다.
처음 vector 를 알았을때 이름을 왜 동적배열 같은걸로 짖지 않았을까 의문이 들었는데..
아래 글을 보면 Alex's lesson 자신도 네이밍 실수를 인정하고, 이름 질때 신중해야한다고 조언도 한다.ㅋ

원문 : https://stackoverflow.com/questions/581426/why-is-a-c-vector-called-a-vector/758548#758548

It's called a vector because Alex Stepanov, the designer of the Standard Template Library, was looking for a name to distinguish it from built-in arrays. He admits now that he made a mistake, because mathematics already uses the term 'vector' for a fixed-length sequence of numbers. Now C++0X will compound this mistake by introducing a class 'array' that will behave similar to a mathematical vector.

Alex's lesson: be very careful every time you name something.

linux write atomic

리눅스에서 멀티 프로세스가 하나의 파일에 쓰기 작업을 할 경우 어떻게 될까?
우선 파일쓰기시 fprintf, fwrite, 등의 C standard library 에서 제공하는 함수를 사용할 수 도 있고 write 와 같은 시스템 함수를 사용할 수 도 있다.
fprintf 의 경우 내부 버퍼링을 하고 write 시스템 콜을 수행하게 된다.

참고

write 함수의 경우 파일이 추가 가능 모드로 열렸다면 파일의 끝 offset 과 쓰기 연산은 atomic 하게 동작한다고 한다.
POSIX.1(.1 은 C standard library 를 규정, .2 shell 관련 규정)에 따라 SSIZE_MAX 까지 쓸 수 있다고 한다. 

SSIZE_MAX 는 /usr/include/bits/posix1_lim.h 에 정의 되어 다음과 같이 정의 되어 있다.
#ifndef SSIZE_MAX
# define SSIZE_MAX  LONG_MAX
#endif

LONG_MAX 는 /usr/include/limits.h 에는 /bits/posix1_lim.h 를 포함하고 있고 다음과 같이 정의 LONG_MAX 가 정의 되어 있다.
#  if __WORDSIZE == 64
#   define LONG_MAX 9223372036854775807L
#  else
#   define LONG_MAX 2147483647L
#  endif

64비트 머신에서 다음과 같이 프로그래밍 해보면
#include <stdio.h>
#include <limits.h>
int main()
printf("SSIZE_MAX : %ld\n", SSIZE_MAX);
return 0;
}

SSIZE_MAX : 9223372036854775807 결과를 보인다.

결국 다음과 같이 write 로 파일 쓸때는 64비트머신에서 거의 무한대로 쓸 수 있는데
On Linux, write() (and similar system calls) will transfer at most 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actually transferred.(This is true on both 32-bit and 64-bit systems.)

문제는 3.14 이전 커널에서 atomic 하지 않다는 문제가 있다고 한다.

BUGS
Among the APIs subsequently listed are write() and writev(2).  And the effects that should be atomic across threads (and processes) are updates of the file offset.  However, on Linux before version 3.14, this was not the case: if two processes that share an open file description (see open(2)) perform a write() (or writev(2))at the same time, then the I/O operations were not atomic with respect updating the file offset, with the result that the blocks of data output by the two processes might (incorrectly) overlap. This problem was fixed in Linux 3.14.

참고 리눅스 바닐라 커널(kernel) http://man7.org/linux/man-pages/man2/write.2.html

여기서 파일 오동작의 경우가 2개가 있는데
interleave(끼우다) : 데이터 쓰는중에 다른 데이터가 껴들어간것
overlap(겹치다): 데이터를 쓰는중 다른 데이터가 덮어 써지는것
위에서 설명한건 offset 이 atomic 하지 않아 overlap 된다는것.
uname -r 로 확인해보면 3.10.0 버전을 사용하는데 어떻게 될지...?
멀티 쓰레드 환경에서 하나의 파일에 동시 쓰기 테스트

https://github.com/ysoftman/test_code/blob/master/cpp/multi_thread_write_same_file.cpp
로 테스트 하니 멀티쓰레드에서는 문제가 없고 멀티 프로세스 환경에서 fprintf()를 사용시문제가 발생한다.

리눅스 버전 의미 참고 http://unix.stackexchange.com/questions/9743/numbering-convention-for-the-linux-kernel

테스트 환경은 centos7 이고 커널버전은 3.10.0-514.6.2.el7.x86_64
centos 에서는 기본 리눅스 바닐라 커널(3.10.0)을 베이스로 하고 이슈가 발생된 부분은 패치 적용하는 방식을 취한다고 한다. 그래서 3.10 버전이지만 위와 같은 오래전 이슈는 이미 수정되어 반영된것으로 보인다.

vscode c++ formatting

# vscode cpp extenstion 을 설치하고 코드 포맷팅을 하면 엉뚱하게 포맷팅이 된다.
# 이유는 포맷팅 환경이 설정되어 있지 않아서이다.
# 우선 clang-format 을 설치하자.
brew install clang-format

# 사용자설정(settings.json) 을 다음과 같이 설정한다.
"C_Cpp.clang_format_path": "/usr/local/bin/clang-format",

# 현재 프로젝트에 .clang-format 파일을 읽어 들인다.
"C_Cpp.clang_format_style": "file",

# format_style 실패시 기본 셋팅(Visual Studio, LLVM, Google, Chromium, Mozilla, WebKit)
"C_Cpp.clang_format_fallbackStyle": "Visual Studio"

# 참고

build boost

# boost 최신 파일 다운
wget https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.tar.gz

# 또는
curl -OLv https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.tar.gz

# 압축풀고 bootstrap.sh 실행
tar zxvf boost_1_62_0.tar.gz
cd boost_1_62_0/
./bootstrap.sh

# b2, bjam 등의 생성되며, b2 에 옵션 프로퍼티 타겟으로 빌드 후 설치
# b2 [options] [properties] [targets]
# target : install
# option : /usr/local에 설치(default)
# properties : gcc컴파일러, c++11사용, 디버그, 64비트머신, 멀티쓰레드
sudo ./b2 --prefix="/usr/local" toolset=gcc cxxflags="-std=c++11" variant=debug address-model=64 threading=multi install

# 타겟 파일 삭제
# 옵션 설명은 ./b2 --help
./b2 --clean-all

# 라이브러리 경로 추가
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

# 참고
http://www.boost.org/build/doc/html/bbv2/overview/invocation.html
http://stackoverflow.com/questions/18452723/change-boost-build-jamfile-for-c11-support

#####

# 패키지 관리자를 이용한 boost 설치
# centos
sudo yum install boost boost-devel

# ubuntu
sudo apg-get install libboost-all-dev

vscode c++ code navigation

vscode c++ 파일을 열었을때 코드 정의 가기(네비게이션)이 안될 수 있다.
c++ 기본 라이브러리 외에 커스텀 라이브러리를 사용하는 경우 그 include 경로를 다음과 같이 지정해야 한다.

0. cpptools 이름의 익스텐션을 검색해 설치해야 한다.
1. include 문에서 경로를 찾을 수 없으면 구불구불한 녹색 밑줄이 표시된다.
2. 밑줄 -> 전구 -> "Add include path to settings" 클릭
3. .vscode/c_cpp_properties.json 이 생성된다.
4. mac/linux/win32 환경에 따라 includePath 에 경로를 추가한다.

참고 https://code.visualstudio.com/docs/languages/cpp

DOS Turbo C

ms-dos 에서 내게 c 프로그래밍의 문을 열어준 borland turbo c 2.0 지금봐도 정말 잘 만들었다. 
프로그래밍 언어는 microsoft gw-basic 을 먼저 접했지만 뭔가 실행 바이너리(.exe)를 만들고 학창시절 더 재미를 느꼈던건 turbo-c 였다.

dosbox 환경에서 Borland Turbo C 실행 화면

컴파일 : F9
실행 : Ctrl + F9 (dosbox 에서 종료 단축키와 같기 때문에 dosbox에는 단축키를 사용하지 말자.)
도스 실행화면 보기 : Alt + F5


플로피디스크 이미지(.img) 파일의 경우 7zip 프로그램으로 열 수 있다.

C Coding Convention and Naming Notation

# BSD Convention(style)
# 버클리 대학교 Eric Allman 프로그램머의 이름을 따 Allman 스타일이라고도 한다.
# 함수와 조건문 반복문 모두 중괄호 시작 위치가 뉴라인에서 시작한다.
# 장점: 중괄호의 시작 위치가 일관적이라 코드 읽기가 쉽다.
# 단점: 라인 수 증가

int funcA()
{
 if (condition > 0)
 {
  result = 1 + 1;
 }
}

# K&R(Kernighan and Ritchie) Convention(style)
# C 언어를 만드신 두분의 이름을 딴 스타일로
# 함수에는 BSD 와 같이 중괄호 시작위치가 뉴라인에서 시작하지만
# 조건문과 반복문에서는 공백후 시작한다.
# 장점: 코드량(라인수) 감소
# 단점: 중괄호 시작 위치에 일관성이 없어 BSD 에 비해 코드 읽기가 어렵다.
int funcA()
{
 if (condition > 0) {
  result = 1 + 1;
 }
}

# 참고로 함수 이름 과 { 시작 전에 파라미터를 선언하는 것으로
# K&R(Kernighan and Ritchie) old(obsolete)스타일로 거의 사용하지 않는다.
int func1(int_param, char_param)
int int_param;
char *char_param;
{
    printf("%s int_param=%d char_param=%s\n", __FUNCTION__, int_param, char_param);
    return 0;
}

# 기타 스타일
https://en.wikipedia.org/wiki/Indentation_style

# 헝가리언 표기법
# MS 프로그래머인 Charles Simonyi  가 사용한 이름 표기 방식으로 특수한 prefix 를 사용한다.
bool bFlag;
char *pName;
char cChar;
char szName[10];
int nIndex;
float fNum;
class CClass

# 카멜(Camel) 표기법
# 소문자로 시작해서 단어 사이를 대소문자로 구별한다.
void myTestFunction() {}

# 파스칼(Pascal) 표기법
# 첫번째 문자를 대문자로 시작한다.
void MyTestFunction() {}

C++ 헤더파일(.h) 중복 include 방지 방법 장단점

# 헤더파일(.h)이 중복 포함되어 불필요한 컴파일 시간이 늘어나는 것을 막기 위해 2가지 중복 포함 방지 방법이 있다.
# 첫번째 .h 중복 포함 방지
# 컴파일러에 따라 지원(Visual C++ 5.0 이상)안될 수 있지만 간결하게 사용할 수 있다.
#pragma once

# 두번째 .h 중복 포함 방지
# 코딩 줄 수가 첫번째 방법보다 많지만 표준이기 때문에 컴파일러에서 상관없이 사용할 수 있다.
#ifndef __YSOFTMAN_H__
#define __YSOFTMAN_H__
...
#endif

64bit data model int , long size

참고: http://www.unix.org/version2/whatsnew/lp64_wp.html
데이터모델에 따라 int , long 의 크기가 다르다

DataModel    char    short    int    long    long long    pointers/size_t    OS(64bit)
LP64             8        16        32    64        X              64                      Unix, Solaris, Linux, Mac OS
LLP64           8        16        32    32        64             64                      MS-Windows
ILP64            8        16        64    64        X              64
LP64 는 long 과 pointer 만 64bit 라는 표시
LLP64 는 long long 과 pointer 만 64bit 라는 표시
ILP64 는 int 와 long 과 pointer 만 64bit 라는 표시

build OpenCV

# 윈도우 빌드
# CMake download
http://www.cmake.org/

# OpenCV download
http://opencv.org/

# CMake 실행
# Where is the source code: 항목에 소스 경로 명시
# Where to build the binaries: 결과파일이 생성될 경로 명시
# Configure 실행하여 컴파일러 선택 후 finish
# Configure Done 후 Generate 실행하면 .sln .vcproj 등의 파일이 생성된다.
# VS2008 의 경우 OpenCV.sln 를 열고 일괄빌드에서
# ALL_BUILD 프로젝트 빌드하면
# bin => *.dll *.pdb 생성됨
# lib => *.lib *.exp 생성됨

#####

# 리눅스 빌드
# CMake 설치
sudo yum install cmake

# OpenCV download
wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/2.4.2/OpenCV-2.4.2.tar.bz2?r=http%3A%2F%2Fopencv.org%2Fdownloads.html&ts=1344324014&use_mirror=cdnetworks-kr-2

# OpenCV 압축 풀기
tar -jxvf OpenCV-2.4.2.tar.bz2

# OpenCV-2.4.2 위치(CMakeLists.txt 위치)에서
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .

# Make파일이 생성되면
make -j10
sudo make install
/usr/local/lib 에 *.so 파일이 생성됨

C++ JSON Library BenchMark

C++ 용 JSON 라이브러를 벤치마크한 블로그
http://lijoblogs.blogspot.com/2011/11/comparison-and-benchmark-of-c-json.html

build MongoDB C++ Client

[윈도우 빌드]
boost : http://sourceforge.net/projects/boost/files/boost-binaries/1.42.0/
python : http://www.python.org/download/
scons : http://www.scons.org/
SpiderMonkey : http://www.mongodb.org/download/attachments/1474760/js.zip
mongodb source : http://www.mongodb.org/downloads
mongovue: http://www.mongovue.com/downloads/

vcvarsall.bat 위치를 환경변수에 추가 (C:\Program Files (x86)\Microsoft Visual Studio 9.0\vc\)
scons 위치를 환경변수에 추가(C:\Python26\Scripts)
콘솔에서 visual c++ 컴파일러를 사용하기 위해서 vcvarsall.bat 실행
D:\ysoftman\Project\mongodb-src-r2.0.2\js 에 SpiderMonkey 압축 풀기
D:\ysoftman\Project\mongodb-src-r2.0.2\SConstruct 에서 find_boost() 부분 수정
    def find_boost():
        for x in ('', ' (x86)'):
            #boostDir = "C:/Program Files" + x + "/boost/latest"
     boostDir = "D:/ysoftman/Project/mongodb-src-r2.0.2/boost_1_42_vs2008_partial_prebuilt/"

mongoclient.lib 생성(release 버전 32bit 용으로)
D:\ysoftman\Project\mongodb-src-r2.0.2\scons mongoclient --release --32

SConstruct 파일의 /MDd --> /MTd 로 수정
mongoclient.lib 생성(debug 버전 32bit 용으로)
D:\ysoftman\Project\mongodb-src-r2.0.2\scons mongoclient --dd --32
D:\ysoftman\Project\mongodb-src-r2.0.2\client\*.h 헤더파일 사용

[빌드 후 신경써야 할것들]
멀티바이트환경에서는 log.h 파일의 399 line LPTSTR --> LPWSTR 로 변경
pch.h 파일 위부분에 보면 에 다음의 내용이 있다.
#define WIN32_LEAN_AND_MEAN
# include <winsock2.h> //this must be included before the first windows.h include
# include <ws2tcpip.h>
# include <wspiapi.h>
# include <windows.h>
WIN32_LEAN_AND_MEAN 는 중복되는 파일을 줄여 주는 역할로 처음에 컴파일된 파일이후에 같은 내용을 무시하도록 한다.
MongoDB 는 윈속2(windosock2.h) 를 사용하지만 windows.h 에는 기본적으로 윈속1(winsock2)를 사용한다.
따라서 WIN32_LEAN_AND_MEAN 를 정의하고 아래처럼 winsock2.h 가 windows.h 보더 먼저 오게된다.
그리고 .pch.h 파일을 가장 먼저 컴파일되어야 한다.

[리눅스 빌드]
1. mongodb 압축 풀기
   unzip mongodb-src-r2.0.4.zip
2  필요한 툴 설치
   sudo yum install scons gcc-c++ glibc-devel boost boost-devel pcre-devel js-devel readline-devel
3. libmongoclient.a 생성(참고로 mongodb 빌드시:  scons all)
   scons mongoclient -j 8

Java JNI(Java Native Interface)

# JNI java 코드

# JNI(Java Native Interface) java 에서 사용할 C 코드

java 바이트코드인 JNITest.class 를 다음과 실행시킨다.(32bit java 가상머신을 사용)
java JNITest

참고로 JNI 사용할때 C코드(.dll) 디버깅 하려면...
Visual C++ 프로젝트에서 다음과 같이 설정한다.
속성 -> 디버깅 -> 명령 : C:\Program Files (x86)\Java\jdk1.7.0_15\bin\java.exe
속성 -> 디버깅 -> 명령인수 : JNITest
속성 -> 디버깅 -> 작업디렉터리 : JNITest 클래스가 위치한곳

이제 VC++ 에서 F5로 디버깅 시작~

Visual C++ Make multi process(job) option

컴파일을 빠르게 하기 위해서 멀티 프로세스 옵션을 사용한다.
예를 들어 8개의 프로세스로 컴파일을 실행한다면 아래와 같다.

[Windows 에서 Visual Studio C++ 를 사용할 경우]
프로젝트 속성 -> C/C++ -> 명령줄 -> 추가 옵션 -> /MP8
단, /MP 옵션을 사용하기 위해선 /Gm /Yc 옵션을 사용하지 말아야 한다.
/Gm 은 변경된 소스파일만 다시 컴파일하는 옵션으로 프로젝트 속성 -> C/C++ -> 코드생성 -> 최소 다시 빌드 기능 에서 선택한다.(VS2008기준)
/Yc 은 미리 컴파일된 헤더 만드는 옵션으로 프로젝트 속성 -> C/C++ >미리 컴파일된 헤더 만들기/사용 에서 선택한다.(VS2008기준)

[Linux 에서 Make 를 사용할 경우]
make -j8

C++ library(.dll .so) load and unload

// .dll .so 라이브러리 로드
#ifdef _WINDOWS
#include <windows.h>
#elif _LINUX
#include <dlfcn.h>
#endif
#ifdef _WINDOWS
HMODULE    m_hdll_MyModule;
#elif _LINUX
t_pVoid    m_hdll_MyModule;
#endif
IModule*   m_pMyModule;

typedef void* (*pvFunctv)();
pvFunctv CreateMyModule;
t_Char dll_path[1024] = "./";

// dll(so) 로딩하기
#ifdef _WINDOWS
strcat(dll_path, "MyModule.dll");
m_hdll_MyModule = LoadLibrary(dll_path);
#elif _LINUX
strcat(dll_path, "libMyModule.so");
m_hdll_MyModule = dlopen(dll_path, RTLD_LOCAL | RTLD_LAZY);
#endif

// dll(so) 인스턴스 가져오기
#ifdef _WINDOWS
CreateMyModule = static_cast<pvFunctv>((t_pVoid)GetProcAddress(m_hdll_MyModule, "GetInstance"));
#elif _LINUX
CreateMyModule = (pvFunctv)dlsym(m_hdll_MyModule, "GetInstance");
#endif
m_pMyModule = static_cast<IModule*>(CreateMyModule());

// dll(so) 사용하기
// 중략...

// dll(so) 해제하기
#ifdef _WINDOWS
FreeLibrary(m_hdll_MyModule);
#elif _LINUX
dlclose(m_hdll_MyModule);
#endif

#####

// 윈도우 환경에서 .dll 을 사용하거나 리눅스 환경에서 .so 를 사용할때
// library 생성 전에 초기화를 하거나 library 사용이 끝나고 리소스를 해제하려면 아래와 같은 방법을 사용한다.
int gInstance = 0;

#ifdef _WINDOWS
int WINAPI DllMain(HINSTANCE hinst, unsigned long reason, void*)
{
    hinst;
    switch(reason)
    {
        case DLL_PROCESS_ATTACH: // 프로세스가처음접근할때
            gInstance = 100;
            break;
        case DLL_PROCESS_DETACH: // 프로세스가접근을해제할때
            gInstance = 0;
            break;
        case DLL_THREAD_ATTACH:  // 쓰레드가처음접근할때
            break;
        case DLL_THREAD_DETACH:  // 쓰레드가접근을해제할때
            break;
    }
    return 1;
}

#elif _LINUX
void __attribute__ ((constructor)) LoadSo() // 프로세스가처음접근할때
{
    gInstance = 100;
}
void __attribute__ ((destructor)) UnLoadSo() // 프로세스가접근을해제할때
{
    gInstance = 0;
}
#endif

#####

C/C++ iconv euc-kr to utf-8

download iconv library ( http://www.gnu.org/software/libiconv/ )
tar -zxvf libiconv-1.12.tar.gz
cd libiconv-1.12
./configure --enable-FEATURE=yes --enable-static=yes --enable-shared=yes --enable-extra-encodings=yes
make

// iconv C 예제
#include <errno.h>
#include "iconv.h"

// UTF-8 로 인코딩하여 저장하기
// UTF-8 의 크기는 EUC-KR 의 약 3배 정도이다.
size_t szIn = strlen(pContents) + 10;
size_t szOut = szIn * 3;
char *pIn = new char[szIn];
char *pOut = new char[szOut];
memset(pIn, '\0', sizeof(char)*szIn);
memset(pOut, '\0', sizeof(char)*szOut);
strcpy(pIn, pContents);
char *pIn2 = pIn;
char *pOut2 = pOut;

iconv_t cd;
int ret;
// EUC-KR 을 UTF-8 로
// 변환될코드의 문자열에 "//IGNORE" 문자열을 추가하여 변환될수 없는 문자에 대해서는 무시하도록 한다.
if ( (cd = iconv_open("UTF-8//IGNORE", "EUC-KR")) < 0 )
{
    // iconv_open 에서 error 나면 errno 을 셋팅한다.
    fprintf(stderr, "Fail to iconv_open() errorno : %d\n", errno);
    exit(-1);
}
// 변환하기
if ( (ret = iconv(cd, &pIn2, &szIn, &pOut2, &szOut)) < 0 )
{
    // iconv 에서 error 나면 errno 을 셋팅한다.
    // E2BIG *outbuf에 공간이 부족합니다
    // EILSEQ 부정확한 다중바이트 문자열이 입력값으로 들어왔습니다.
    // EINVAL 완료되지않은 다중바이트문자열이 입력값으로 들어왔습니다.
    char errmsg[10] = "";
    if (errno == E2BIG) sprintf(errmsg, "E2BIG");
    if (errno == EILSEQ) sprintf(errmsg, "EILSEQ");
    if (errno == EINVAL) sprintf(errmsg, "EINVAL");
    fprintf(stderr, "Fail to iconv() errorno : %s(%d)\n", errmsg, errno);
}
iconv_close(cd);

// iconv() 처리 후 szOut 크기를 재계산해야 한다.
// iconv() 는 pIn2 를 szIn 크기가 0이 될 때까지 처리한다.
szOut = pOut2 - pOut;
FILE *fp = fopen("test.txt", "wb");
fwrite(pOut, 1, szOut, fp);
delete[] pIn;
delete[] pOut
fcloe(fp);