C/C++ 코딩 시 변수끼리 값을 바꾸고 싶은 경우들이 있습니다.

 

이를 보통 변수 swap 이라고 하는데

 

a, b 라는 두 변수간에 값을 바꾸기 위해서는 보통 하나의 변수가 더 필요 합니다.

 

temp 라는 하나의 변수를 더 써서 다음과 같이 변경하는 게 일반적이죠. 비트 연산을 하지 않는 실수 타입들은 아래 방식으로 하는 게 맞을 겁니다.

 

temp = a;

a= b;

b= temp;

 

하지만 정수 타입의 경우 비트 연산을 이용하여 temp 라는 추가적인 변수 없이 swap 이 가능 합니다.

 

아래와 같이 Exclusive OR 연산을 세 번 사용하면 변수끼리 값을 바꿀 수 있습니다.

 

#define SWAP(a, b)  a ^= b; b ^= a; a ^= b;

 

위 매크로에 대해 다음과 같이 테스트 해 봤습니다.

 

#include <iostream>

using namespace std;

 

#define SWAP(a, b)  a ^= b; b ^= a; a ^= b;

int main()

{

    int x = 10;

    int y = 5;

    SWAP(x, y)

    cout << "x=" << x << " y= " << y << endl;

    return 0;

}


결과는 다음과 같이 x, y 값이 바뀐 것을 확인 할 수 있습니다.


x=5, y= 10



오늘은 좀 독특한 언어에 대해 소개해 드리려 합니다.

 

해당 언어의 이름은 DRAKON editor 라고 하고 홈페이지는 아래 주소와 같습니다.

 

http://drakon-editor.sourceforge.net/

 

DRAKON editor는 아래 그림과 같이 그래프를 사용해서 코딩을 하는 툴이라 할 수 있습니다.

 

홈페이지에서도 visual language 라고 되어 있네요. 홈페이지에는 러시아 우주 프로그램에 사용되었다고 하는데~ 요즘 자동차 쪽에서 이슈인 MBD(Model Based Design)와 비슷한 컨셉으로 보였습니다.

 

그런데 약간 사용을 해보니 완전 그렇지는 않은 게 MBD의 경우 MATLAB Simulink 등을 통해 그래프를 그리면 코드가 나오는 형태임에 반해 DRAKON editor 는 그래프를 그리고 해당 부분에 코드를 넣어줘야 하는 형태였습니다.

 

그래도 그래프를 통해 코드를 작성하니 코드의 흐름이 굉장히 명확해 져서 좋은 것 같다고 생각했습니다. DRAKON editor 에서는 C/C++, C#, Java, Erlang, Python, Tcl, Lua 에 대한 코드 생성이 가능했습니다.

 

아래 주소를 통해 다운로드 후에 설치 가능합니다.

 

http://drakon-editor.sourceforge.net/editor.html#downloads

 

DRAKON editor는 Tcl 로 만들어 졌고 Windows, Mac, Linux 에서 동작하는 Cross Platform 툴 입니다.

 

저는 현재 Windows 64비트를 사용하고 있는데 아래 그림에서와 같이 Active Tcl 을 다운로드 받아서 설치를 하고 drakon_editor1.26.zip 를 다운로드 받아서 압축을 푼 후에 drakon_editor.tcl 파일을 실행했습니다.

 

압축을 풀면 examples 폴더에 다양한 언어에 대한 예가 나와 있습니다.

 

DRAKON editor 를 실행해보면 다음과 같은 창이 나타납니다.

 

위 그림에 나와 있는 바와 같이 DRAKON editor 는 Save 버튼이 없습니다. 그래서 무조건 파일부터 만들고 실행을 해야 합니다. 파일에 수정 되는 부분들은 자동으로 저장이 됩니다.

 

저는 업무상 C 로직을 주로 구성하므로 아래 페이지의 tutorial 을 봤습니다.


http://drakon-editor.sourceforge.net/cpp/c.html

 

C 언어에서 흔히 사용하는 if, switch, 반복 문 등에 대해 구성이 가능 하고~

 

CTRL + B 를 누르거나 Generate Code 을 눌러서 코드를 생성 할 수 있습니다.

 

위 루프 문에 대해 PrintStringsFrom.c, PrintStringsFrom.h 파일이 생성됩니다. 생성된 파일을 열어 보면~~

 

for 문으로 구성 될 거라 생각했었는데~ 다음과 같이 goto 문으로 반복문이 구성되더군요.

 

지금까지 C 코딩을 하면서 이런 식으로 루프를 구성해 본적은 없었던 터라 첨에는 이게 뭔가 했었는데

 

이렇게도 할 수 있구나 생각하니 재미 있더군요. 글쎄…… For 로 구성하는 것과 goto 로 구성하는 것 중 어떤게 더 좋은 코딩 방식인지는 잘 모르겠네요.

 

오늘은 Eclipse 플러그인 주에 제가 요즘 유용하게 사용하고 있는 Bracketeer 라는 플러그 인에 대해 소개하려 합니다.

 

Bracketeer 플러그인은 괄호 또는 중괄호의 짝을 맞춰 주는 플러그인 입니다.

 

Source Insight 와 같은 에디터를 사용해 보신 분들이라면 쉽게~ 아~~ 이거구나~ 하실 겁니다.

 

홈페이지는 아래 주소와 같습니다.

 

http://marketplace.eclipse.org/content/bracketeer-cc-cdt

 

설치는 Market Place 에서 Bracketeer 라고 검색을 해보면 아래와 같이 Java 용과 CDT 용이 나옵니다. 저는 현재 C/C++ 을 주로 사용해서 cdt 용을 설치 했습니다.


 

설치가 다 끝나면 다음과 같이 Bracketeer 관련한 아이콘들이 생성되고~ 코드에서 보는 바와 같이 해당 중괄호가 어떤 코드의 끝 부분인지가 자동으로 표시 됩니다.

 

요즘은 툴들이 많이들 좋아져서 그런 경우는 별로 없지만 괄호의 짝이 안 맞아서 에러 나는 경우는 많이 줄어들겠죠~

C/C++ 코딩 시 비트 연산은 굉장히 많이 하지만 자주 실수하는 부분입니다.

 

이런 비트연산들은 임베디드 시스템 설계시 자주 사용하곤 하는데 자주 사용하는 만큼 매크로로 만들어서 사용하면 편리하겠쬬.

 

제가 사용하는 비트연산 매크로는 다음과 같습니다.

 

필요하신 분들은 사용하시길~


C/C++ 코드를 버전에 따라 다른 형식으로 작성해야 할 경우가 종종 있습니다.

 

예를 들어 어떤 경우에는 주석을 다 지우고 전달해야 하는 경우가 있는데~

 

이런 경우를 위해 파이썬으로 C/C++ 주석 지우는 코드를 만들어 봤습니다.

 

아래 코드에서 workingDir = "D:\TestFolder" 부분을 코드가 들어있는 최상위 폴더로 맞춰 주면 *.c, *.h 파일의 모든 주석을 지워줍니다.

 

C++ 코드 라면 AllFileList 부분에서 *.CPP 와 같은 확장자를 추가해 주면 됩니다.

 



코딩을 할 때 Ctags 와 같이 해당 코드로 점프하는 기능이나, 프로젝트에 대한 폴더 구조를 쉽게 볼 수 있는 기능들이 필요한데요~

 

오늘은 Notepad++에서 이러한 기능들을 쉽게 사용할 수 있도록 해주는 플러그인들에 대해 소개하려 합니다.

 

Notepad++ 에서 탐색기와 같이 폴더 구조를 보여주는 플러그인은 Explorer 를 사용하시면 됩니다. 플러그인 → Plugin Manager 에서 아래 그림과 같이 Explorer를 선택한 후에 Install 을 해주시면 설치 됩니다.

 

설치 후에 플러그인 → Explorer → Explorer 를 클릭해 주시거나 아래 그림에서 보이는데로 보이는데로 Ctrl+Alt+Shift+E 를 누르시면 옆에 폴더 구조가 보여 집니다.

 

또한 Go to Path를 누르면 아래 그림과 같이 해당하는 Path 로 쉽게 이동할 수 있습니다.

 

다음으로 C/C++ 의 헤더와 소스 코드 간에 이동을 편하게 해 주는 SourceSwitch 와 Ctags 와 같이 해당 변수나 함수들로 이동하게 해주는 Source Cookifier에 대해 소개하겠습니다.

 

아래 그림과 같이 Source Cookifier, SourceSwitch를 설치합니다. 마찬가지로 install 을 눌러 주면 됩니다.

 

SourceSwitch 는 F9 를 눌러주면 C/C++ 코드의 헤더파일에서 소스파일로 소스에서 헤더 파일로 이동 할 수 있게 해줍니다.

 

또한 점프 하려는 헤더에 커서를 둔 상태에서 F10을 누르면 해당되는 헤더 파일로 이동하게 되며~

 

아래 그림과 같이 Set Top Level 을 클릭하고 프로젝트의 최 상위 폴더를 설정해 놓으면 그 이하의 코드들을 인덱싱해서~~ 파일들이 여러 폴더로 나누어져 있을 때 더욱 편리하게 사용할 수 있습니다.

 

다음으로 Ctags 와 같이 해당 변수나 함수들로 이동하게 해주는 Source Cookifier를 간단하게 알아보겠습니다.

 

Source Cookifier는 아래 그림과 같이 Toggle Source Cookifier 버튼을 클릭하면 그림과 같이 나타나게 됩니다.

 

3가지의 모드가 있는데요~ Single file mode, N++ session mode, Cookie session mode 가 있습니다.

 

Single file mode 는 말 그대로 파일 하나에 대해서만 표시 되고~ N++ session mode 모드에서는 현재 열려 있는 다수의 파일들에 대해 각종 함수나 변수들이 표시가 됩니다.

 

보통 개발하시는 분들이라면 Cookie session mode 를 주로 사용하시게 될 텐데요~

 

Cookie session mode 를 사용하려면 Source Cookifier 에 아래 그림과 같이 tag 하려는 파일들을 드래그 합니다.

 

그럼 Import 할거냐고 물어보는데 당연히 Yes 를 하면 되겠죠~

 

다음으로 해당 Cookie session을 아래 그림과 같이 save 를 눌러서 파일로 저장합니다.

 

파일 확장자는.c00k!e 입니다. 저는 tag1.c00k!e 라는 이름으로 저장했습니다.

 

Cookie session mode 는 여러 폴더에 소스들이 나눠져 있는 경우 대단히 편리하게 사용할 수 있을 것 같더군요.

 

다음에 또 사용할 때는 아래 그림과 같이 해당 c00k!e 확장자 파일을 로드해서 사용하면 되고~ Load 버튼을 눌러서 다른 폴더에 저장되어 있는 tag 파일도 불러와서 사용 할 수 있습니다.



Eclipse 를 사용한 개발은 참 재미있는 것 같다.

 

기본 프로그램에 각종 플러그인들만 추가하면… 대부분의 코딩이 가능하고 그냥 일반적인 에디터에서 코딩하는것에 비해 그 효율성이 확실히 배가 된다.

 

뭐 사람들이 많이 사용하는데는 다~~ 그 나름의 이유가 있는 법!!

 

아래 글에서 밝힌 바와 같이 현재 나의 Eclipse 버전은 Kepler (4.3) 이다. 

2013/09/29 - [컴퓨터일반] - Eclipse Kepler upgrade 방법


플러그인 설치 방법들은 무지하게 간단한데~ Help → Install New Software 에 들어가서 각 플러그인들의 주소를 설정해 주고 install 해 주면 된다.

 

  • C/C++ 코딩을 위한 CDT 플러그인

 

각 버전별 CDT 플러그인 들은 아래 주소에서 확인 가능하다.

http://www.eclipse.org/cdt/downloads.php

CDT - http://download.eclipse.org/tools/cdt/releases/kepler/

 

  • Perl 코딩을 위한 Eclipse 플러그인 EPIC

http://www.epic-ide.org/download.php

EPIC - http://e-p-i-c.sf.net/updates

 

  • Python 코딩을 위한 Eclipse 플러그인 pydev

http://pydev.org/manual_101_install.html

PYDEV - http://pydev.org/updates

 

  • php 코딩을 위한 Eclipse 플러그인 PDT

http://www.eclipse.org/pdt/downloads/

PDT - http://download.eclipse.org/tools/pdt/updates/release

 

  • 안드로이드 코딩을 위한 Eclipse 플러그인

http://developer.android.com/sdk/installing/installing-adt.html

ADT - https://dl-ssl.google.com/android/eclipse/

 

  • APTANA 설치를 위한 Eclipse 플러그인

APTANA - http://download.aptana.com/studio3/plugin/install


저는 윈도우 환경에서 C/C++ 코딩을 할 때 MinGW 등을 이용하곤 하는데요~

 

아래 포스팅들에서 밝힌바와 같이 C/C++ 코딩시 CodeBlocks 를 주로 사용해 왔습니다.

 

2013/01/20 - [유틸] - Code::Blocks 12.11 좋아졌네요.


2013/01/01 - [유틸] - Code::blocks에서 SQLite3사용하기


2012/08/26 - [컴퓨터일반] - CodeBlock 에서 FFTW 라이브러리를 사용한 FFT 실습


2012/07/31 - [컴퓨터일반] - Codeblock 에서 DLL 사용하기


cbp2make 등을 이용해서 Makefile 도 생성할 수 있고 굉장히 가벼워서 편리하더군요.

 

2012/12/06 - [유틸] - Codeblock Project 에서 C/C++ Makefile 만들기, cbp2make

 

하지만 아무래도 대다수의 사람들은 Eclipse 를 사용하는데... 프로그램이 무겁긴 해도 그 편리성은 정말 뛰어나더군요.

 

오늘은 Eclipse 에서 Makefile 생성하는 방법에 대해 간단히 소개하려 합니다.

 

처음에 윈도우에서 MinGW 사용해서 C/C++ 프로젝트 생성시 Makefile 은 생성이 되지 않더군요.

 

그래서 Codeblocks 처럼 cbp2make 같은 프로그램을 이용해서 Eclipse 프로젝트 파일로 부터 Makefile 을 생성해 줘야 하나라는 생각을 했었습니다.

 

그런데 찾아보니 단순 셋팅만 바꿔주면 되는 거더군요.

 

프로젝트를 클릭후에 오른쪽 클릭~ 해서 나오는 팝업 메뉴에서 Properties 에 들어갑니다.

 

그리고 아래 그림처럼 C/C++ Build >> Tool Chain Editor >> Current builder 를 Gnu Make Builder 로 설정합니다.

 

이후에 빌드를 하면~ 아래 그림처럼 해당 되는 Debug 또는 Release 폴더에 Makefile 이 생성됩니다.


C/C++ 코딩시 매크로는 #define 을 사용하여 다음과 같이 정의하곤 합니다.

 

단순하게 상수등을 다음과 같이 정의하곤 하지만~

 

#define PI     (3.141592)

 

상수 뿐만이 아니라 매개변수등도 이용할 수가 있습니다.

 

사용법은 굉장히 단순한데요.

 

다음과 같이 원의 넓이를 구하는 매크로를 구성할 수 있습니다.

 

#define CIRCLE(x) ((x)*(x)*(PI))

 

매크로 정의시에는 항상 모든 부분들을 괄호를 이용하여 꼼꼼하게~ 묶어 주는 게 좋습니다. 그렇지 않으면~~ 까딱 잘못하다가 예상치 못한 결과를 얻을 수 있거덩여~

 

다음으로 # 연산자를 간단하게 소개하겠습니다.

 

이미 많은 분들이 아시겠지만, # 연산자는 매개변수를 문자화 하는 연산자 입니다.

 

다음과 같이 사용합니다.

 

#define STRING(x) #x

 

위와 같이 define 을 하고 STRING(Character) 하면~ " Character" 라고 문자열로 정의한것과 마찬가지 입니다.

 

이제 마지막으로 ## 연산자에 대해 소개해 드리죠~

 

아래와 같이 정의하고~

#define X(n) x##n

 

X(1) 이라고 하면~ 이는 변수 x1 을 입력한 것과 동일합니다. 즉. ## 연산자는 토큰들을 결합하는 역할을 하는거죠.

 

x1, x2, x3 …. 등과 같이 정의하고 싶다면~ ## 연산자를 이용해서 처리 할 수 있겠죠~

 

위 설명한 부분에 대해 간단하게 예제를 만들어 보았습니다.

 

#include <iostream>

 

using namespace std;

 

 

#define PI     (3.141592)

 

#define CIRCLE(x) ((x)*(x)*(PI))

#define STRING(x) #x

 

#define INT_X(n) int x##n = n

#define COUT_X(n) cout << "x"#n" = " << x##n <<endl

 

 

int main()

{

// 원의 넓이

cout << "반지름 4인 원의 넓이 : " << CIRCLE(4) << endl ;

 

// 매크로 # 연산자

cout << "# 연산자 예 : " << STRING(문자열로~) << endl ;

 

// 매크로 ## 연산자

 

INT_X(0);

INT_X(1);

INT_X(2);

INT_X(3);

 

COUT_X(0);

COUT_X(1);

COUT_X(2);

COUT_X(3);

 

 

return 0;

}

 

위 코드를 실행 시켜 보면 다음과 같은 결과가 나타납니다.


#, ## 연산자를 이용한 매크로는 디버그시 특히 유용하다 하더군요~ 


아래 주소에서 macro 에 대한 좋은 예들을 볼 수 있다.  

http://www.cprogramming.com/tutorial/cpreprocessor.html



지난 포스팅에서 memmove() 함수를 이용한 memory shift 실험을 수행했었는데~


  2012/08/06 - [컴퓨터일반] - C/C++ memmove() 함수 속도 실험


memmove() 함수의 속도가 for 문을 이용했을 경우에 비해 그리 빠르지 않은 것을 확인했었습니다.

 

그래서 계속 찾다 보니 C++ STL 에 deque 가 있더군요.

 

디지털 필터 설계시의 memory shift 는 이전 신호는 없애고 현재의 신호가 끝에 들어가는 동작이 반복되기 때문에 C++ STL 의 deque 가 적격이라고 생각되는군요.

 

그래서 얼마나 빠른지 다시 한번 실험을 해봤습니다.

 

본 실험은 컴퓨터 성능에 따라 다르겠지만 for 문, memmove(), deque 사용에 따른 상대적인 속도 차이를 비교하기 위한 것입니다.

 

이전에 사용했던 코드에 다음과 같이 deque 부분을 추가했습니다.

 

실험 결과는다음과 같은데요…디지털 필터 설계시에는 deque 가 진리인 듯…. 의견있으신 분들은 리플 부탁요~


#include <iostream>

#include <stdio.h>

#include <string.h>

#include <time.h>

#include <fstream>

#include <math.h>

#include <deque>


using namespace std;


int main()

{

    time_t start,end;

    double dif, average_time,average_time1, average_time2, sum_time, average_time_deque;

    unsigned k, i;

    unsigned N_sim, N_buffer;


    ofstream fout("abc.txt");


    N_sim=1000000;


    int * test1;

    int N;


    for (N=10;N<17;N++)

    {

        N_buffer=(unsigned)pow(2,N);

        test1 = new int[N_buffer];


        deque<int> dequeBuffer(N_buffer,0);       // deque buffer initialization


        // use for loop


        sum_time=0;


        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time


            for (i=1;i<N_buffer;i++)

            {

                test1[i-1]=test1[i];

            }


            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time=sum_time/(double)N_sim;


        // use memmove, Low to High


        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

            memmove(test1+1, test1,(N_buffer-1)* sizeof(int));

            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time2=sum_time/(double)N_sim;



        // use memmove, High to Low


        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

            memmove(test1, test1+1,(N_buffer-1)* sizeof(int));

            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time1=sum_time/(double)N_sim;



        // use deque


        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

dequeBuffer.pop_front();

     dequeBuffer.push_back(100);


            time(&end);

            dif = difftime(end,start);


            sum_time+=dif;

        }

        average_time_deque=sum_time/(double)N_sim;


        fout << fixed;

        fout.precision(10);

        fout << N_buffer << "\t" << average_time << "\t" << average_time1 << "\t" << average_time2 << "\t" << average_time_deque <<endl;


        cout << fixed;

        cout.precision(10);

        cout << N_buffer << "\t" << average_time << "\t" << average_time1 << "\t" << average_time2 << "\t" << average_time_deque <<endl;


        delete []test1;

    }

    fout.close();

    return 0;

}


  1. 정성진 2013.04.12 17:21

    deque는 버퍼초기화 시간이 함께 포함되어야 정확한 비교가 될 것 같아요.

    • 남성 2013.04.13 18:47 신고

      방문해 주셔서 감사합니다. ^^ 말씀 하신 부분에 대해서도 생각함 해 봐야겠네요.

이전 포스팅에서 memcpy() 함수와 for 문을 이용한 메모리 복사의 속도 실험을 해 본적이 있었는데요.

  

2012/07/16 - [컴퓨터일반] - C/C++ memcpy() 함수 속도

 

오늘은 그 연장선으로 memmove() 함수의 속도 실험을 수행해 봤습니다.

 

memcpy() 함수는 인자로 들어가는 두 메모리가 다른 주소여야 하지만

 

다음과 같은 정의의 memmove() 함수는 source 와 destination 이 같은 주소여도 상관이 없는 것으로 알고 있습니다.

 

void * memmove ( void * destination, const void * source, size_t num );

 

즉 memmove() 함수는 소스가 겹쳐지는 부분에 대해 내부적으로 고려를 해주는 뭔가가 더 들어간다는 거죠.

 

디지털 필터를 설계 할 때 memory shift 구현에 memmove() 를 사용하는 것이 좋을 것 같다는 생각이 들더군요.

 

그래서 다음과 같이 속도 실험을 해 봤습니다.

 

for 문을 사용할 때, 배열의 높은 인덱스에서 낮은 인덱스로 복사 할 때, 배열의 낮은 인덱스에서 높은 인덱스로 복사 할 때, 이렇게 세가지 경우에 대해 비교해 봤는데, 생각보다 속도가 빠르진 않더군요.

 

실험 코드는 다음과 같이 작성했습니다.

 

#include <iostream>

#include <stdio.h>

#include <string.h>

#include <time.h>

#include <fstream>

#include <math.h>

 

using namespace std;

 

int main()

{

    time_t start,end;

    double dif, average_time,average_time1, average_time2, sum_time;

    unsigned k, i;

    unsigned N_sim, N_buffer;

 

    ofstream fout("abc.txt");

    N_sim=1000000;

 

    int * test1;

   

    int N;

    for (N=10;N<17;N++)

    {

        N_buffer=(unsigned)pow(2,N);

 

        test1 = new int[N_buffer];

 

 

        // use for loop

        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

            for (i=1;i<N_buffer;i++)

            {

                test1[i-1]=test1[i];

            }

            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time=sum_time/(double)N_sim;

   

        // use memmove, Low to High

        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

            memmove(test1+1, test1,(N_buffer-1)* sizeof(int));

            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time2=sum_time/(double)N_sim;

           

        // use memmove, High to Low

        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

            memmove(test1, test1+1,(N_buffer-1)* sizeof(int));

            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time1=sum_time/(double)N_sim;

   

        fout << N_buffer << "\t" << average_time << "\t" << average_time1 << "\t" << average_time2 << endl;

        cout << N_buffer << "\t" << average_time << "\t" << average_time1 << "\t" << average_time2 << endl;

   

        delete []test1;

    }

 

    fout.close();

      return 0;

}

 

결과는 이렇게 나오더군요.


memmove  속도 실험

 

실험 결과에서 배열의 높은 인덱스에서 낮은 인덱스로 복사 할 때의 경우에는 for 문을 사용할 때보다 오히려 속도가 느리더군요.

 

배열의 낮은 인덱스에서 높은 인덱스로 복사 할 때는 아주 약간 빠르긴 한데 그리 체감 할 정도는 아닌 것 같습니다.

 

지난 실험에서 memcpy() 함수가 for 문을 사용할 때에 비해 약 5 배 정도 빨랐던 것 같은데 C/C++ 로 memory shift 를 구성할 때 메모리를 하나 더 둬서 memcpy() 함수를 사용하는 것이 속도 면에서는 더 좋을 수 도 있겠다는 생각이 드는군요.

 

의견 있으신 분들은 댓글 남겨 주세요.


  1. imagej 2013.03.12 10:06

    memmove는 사실 잘 사용하지 않는 구문이라 속도를 비교할 기회가 없었는데 포스팅을 보고 예상외 결과네요.

    실제 memcpy 는 for나 while 같은 루프에 비해서 순간적으로 이루어 져서 memmove 역시 빠를거라 생각했는데....

    근데 만일 같은 메모리에서 인덱스를 밀거나 당겨서 이동하는거 보다 서로 다른 메모리에(리스크가 있겠지만...) 무브를 하게되면 내부적으로 복사를 또 할 필요가 없기때문에 더 속도가 나지 않을까 생각이 드네요.

    • 남성 2013.03.12 12:57 신고

      방문해 주셔서 감사합니다. ^^
      저도 memmove 는 잘 사용하지 않긴 했지만 그래도 생각보다 느려서 당황스럽더군요. 아~~ 이래서 memmove 는 잘 안쓰나 싶기도 하고요. memory shift 는 아래 주소에 설명했던 C++ STL 의 deque 가 가장 빠르더군요.
      http://iamaman.tistory.com/631

C/C++ 에서 메모리 복사를 위해서 사용하는 함수로 memcpy() 함수가 있습니다.

 

for 나 while 과 같은 루프를 이용해서 메모리를 복사 할 수 도 있지만, memcpy() 함수를 이용하는 것이 속도 면에서 월등히 빠르다고 하더군요.

 

그래서 오늘 포스팅에서는 memcpy() 와 루프 문을 이용한 메모리 복사의 속도 비교를 해 보려 합니다.

 

memcpy() 함수는 string.h 에 정의 되어 있고 그 원형은 다음과 같습니다.

 

void * memcpy ( void * destination, const void * source, size_t num );

 

source 에서 destination 으로 num 만큼을 복사 하는 간단한 형태입니다.

 

비교를 위해서 배열의 크기에 따른 시뮬레이션을 수행해 봤고, 시험 횟수는 1000000 회를 수행해서 메모리 복사에 걸리는 시간들의 평균을 구해 봤습니다.

 

코드는 다음과 같습니다.

 

#include <iostream>

#include <stdio.h>

#include <string.h>

#include <time.h>

#include <fstream>

#include <math.h>

 

using namespace std;

 

int main()

{

    time_t start,end;

    double dif, average_time,average_time1, sum_time;

    unsigned k, i;

    unsigned N_sim, N_buffer;

 

    ofstream fout("abc.txt");

    N_sim=1000000;

 

    int * test1;

    int * test2;

 

    int N;

    for (N=10;N<17;N++)

    {

        N_buffer=(unsigned)pow(2,N);

 

        test1 = new int[N_buffer];

        test2 = new int[N_buffer];

 

        // use for loop

        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

            for (i=0;i<N_buffer;i++)

            {

                test1[i]=test2[i];

            }

            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time=sum_time/(double)N_sim;

 

 

        // use memcpy

        sum_time=0;

        for (k=0;k<N_sim;k++)

        {

            time(&start); // start time

            memcpy(test2, test1,N_buffer*sizeof(int));

            time(&end);

            dif = difftime(end,start);

            sum_time+=dif;

        }

        average_time1=sum_time/(double)N_sim;

 

        fout << N_buffer << "\t" << average_time << "\t" << average_time1 << endl;

        cout << N_buffer << "\t" << average_time << "\t" << average_time1 << endl;

 

        delete []test1;

        delete []test2;

    }

 

    fout.close();

    return 0;

}

 

시뮬레이션 시간을 측정 해보니 실제로 시간 차이가 꽤 많이 나더군요.

 

컴퓨터 성능에 따라 차이는 있겠지만, 제 컴퓨터의 경우 for 루프를 이용한 경우에 비해 memcpy() 함수를 이용한 경우가 거의 5 배 정도 빠르다는 것을 알 수 있었습니다.






오늘 간만에…… 왠 바람이 불어서인지는 모르겠지만…… Math.h 헤더 파일을 들여다 보게 되었다.

 

예전에는 그냥 무심코 쓰던 헤더였는데…… 이상하게 보고 싶어서 머가 들어있나 들여다 봤다.

 

근데 이런 썩을…… erfc() 함수가 아주 예쁘게 정의되어 있었다.

 

erfc() 함수가 정의되어 있다는 건 Q-function 도 아주 손 쉽게 정의해서 쓸 수 있다는 것이고~~

 

참조: 2011/03/19 - [MATLAB] - MATLAB erf, erfc, Q- function

 
내가 암 것도 모르던 무식한 시절 ~~~ 날 밤 새가며 사다리꼴 적분 법으로 짰던 Q-function 은 단 한 줄로 끝난다는 얘기였다.

 

qfunc()는 다음과 같이 짤 수 있다.

#include <math.h>

 

double qfunc(double v)

{    

    return erfc(v/sqrt(2.0))/2.0;

}


 

오늘의 교훈 1: 모르면 무식하게 코딩 하지 말고~ 일단 찾아봐라…… 웬만한 건 다~~ 있다.

 

오늘의 교훈 2: C 나 C++ 코딩 할 때…… 헤더부터 보는 건 기본 중에 기본이다


'통신' 카테고리의 다른 글

Digital Signal Up Down Conversion  (0) 2012.10.20
[C/C++] Q, erfc function  (0) 2011.10.05
[디지털 통신] Quantization 에 따른 SNR  (0) 2011.05.24
[디지털 통신] QAM mapping & demapping  (4) 2011.04.09
[디지털 통신] BPSK, QPSK  (4) 2011.03.08

C 코딩 시 동적 배열은 malloc() 또는 calloc() 함수를 주로 사용한다.

 

보통 malloc() 함수는 다음과 같이 사용한다.

 





Int * Arr; // 배열에 대한 포인터 선언

 

Arr=(int *)malloc(X * sizeof(int)); // malloc() 함수 이용 동적 배열 선언, X 는 배열의 크기 , Arr[0], Arr[1]… 등으로 각 인자의 값에 접근

 

free(Arr); // 동적 배열 free


 

 

calloc() 함수는 다음과 같이 사용한다.

 

Int * Arr; // 배열에 대한 포인터 선언

 

Arr=(int *)calloc(X , sizeof(int)); // calloc() 함수 이용 동적 배열 선언, X 는 배열의 크기 , Arr[0], Arr[1]… 등으로 각 인자의 값에 접근

 

free(Arr); // 동적 배열 free 

 

malloc(), calloc() 함수의 차이는 calloc() 함수의 경우 초기값을 0으로 셋팅 한다는 거다.

 

두 함수는 stdlib.h 안에 포함되어 있으므로 두 함수를 이용할 때는 파일의 윗줄에 #include <stdlib.h> 를 해 줘야 한다.

 

동적 배열을 이용한 이차원 배열은 다음과 같다.

 

int i, m, n ; // m 행 n 열 배열을 잡기 위한 변수

double** matrix; // double 형 2차원 동적 배열을 잡기 위한 포인터

matrix=( double **)calloc(m, sizeof(double *)); // m 행을 동적 배열로 잡음

 

for (i=0;i<m; i++) // m 행만큼 루프를 돌면서 각 행 마다 n 열씩 동적 배열을 잡음

{

       matrix[i]=( double *)calloc(n,sizeof(double));

}


 

matrix[0] [0], matrix[0] [1] … 과 같이 2차원 배열의 각 인자에 접근

 

 

동적 배열을 해제 할 때는 다음과 같이 한다.

 

for (i=0;i<m;i++)

{

    free(matrix [i]);

}

free(matrix);


 

이상이 C 코딩 시의 2차원 동적 배열 설정 및 해제 방법 이다.

 



그런데 저런 2차원 배열을 여러 개 쓸 때는 매번 저렇게 설정하는 게 짜증 날 것이다.

 

따라서 동적 배열의 설정 및 해제를 함수로 만들어서 사용한다.

 

다음은 Numerical Recipe in C 라는 책에 소개된 동적 메모리 할당 및 해제 하는 함수들이다.

 

double * get_dvector_space(int m) // 1차원 double 형 동적 메모리 할당 , m 행

{

    double* cm;

    cm=(double *)calloc(m,sizeof(double));

    return cm;

}

 

void free_dvector(double* cm) // 1차원 double 형 동적 메모리 해제

{

    free(cm);

}

 

double** get_dmatrix_space(int m,int n) // 2차원 double 형 동적 메모리 할당 , m 행 n 열

{

    int i;

    double** cm;

    cm=(double **)calloc(m,sizeof(double *));

    

    for (i=0;i<m;i++)

    {

        cm[i]=(double *)calloc(n,sizeof(double));

    }

    return cm;

}

 

void free_dmatrix(double** cm, int m) // 2차원 double 형 동적 메모리 해제

{

    int i;

    

    for (i=0;i<m;i++)

    {

        free(cm[i]);

    }

    

    free(cm);

 



Int 형 동적 메모리 할당 및 해제 함수는 저 위의 함수에서 double 만 int 로 바꾸고 함수이름도 dvector 부분을 ivector 등으로 적절히 바꿔서 만들어 주면 될 것이다.


다른 형으로 바꿀 때도 마찬가지다.

 
위 함수를 이용하는 방법은 다음과 같다.

 

double * arr;

arr = get_dvector_space(10); // 1차원 배열 선언

free_dvector(arr); // 해제

  

double ** matrix;

matrix = get_dmatrix_space (10,10); // 2차원 배열 선언

free_dmatrix (matrix, 10); // 해제


 

근데 C 언어에서는 각 변수 타입 마다 저 위와 같은 함수들을 다 만들어줘야 한다. Double 일 때 함수 int일 때 함수 float 일 때 함수 …등... 다 만들어 줘야 한다. ㅡㅡ;

 



이렇게 만들기도 참 귀찮은 일이다.

 

따라서 C++ 로 갈아타서 template 을 사용하자.

 

다음과 같이 template 함수로 선언 할 수 있다.

 

// template_buffer.h 파일

 

#include <stdlib.h>

 

template<typename T>

 

T* get_vector_space(int m)

{

    T* cm;

    cm=(T *)calloc(m,sizeof(T));

    return cm;

}

 

 

template<typename T>

void free_vector(T* cm)

{

    free(cm);

}

 

template<typename T>

T** get_matrix_space(int m,int n)

{

    int i;

    T** cm;

    cm=(T **)calloc(m,sizeof(T *));

    

    for (i=0;i<m;i++)

    {

        cm[i]=(T *)calloc(n,sizeof(T));

    }

    return cm;

}

 

template<typename T>

void free_matrix(T** cm, int m)

{

    int i;

    

    for (i=0;i<m;i++)

    {

        free(cm[i]);

    }

    

    free(cm);

}

 




Template 함수에 대한 내용은 이전 포스팅을 참조하자.

2011/03/06 - [컴퓨터일반] - [C++] template
 



위 함수들을 이용한 간단한 예제 코드는 다음과 같다.

 

// Vector_test.cpp

 

 

#include <stdio.h>

#include "template_buffer.h"

 

 

int main(int argc, char **argv)

{    

    int n, i;

      

    

    double *double_vector, **double_matrix;

    int * int_vector, **int_matrix;    

    

    double_vector = get_vector_space<double>(2);     // double 형 1차원 배열

    int_vector = get_vector_space<int>(2); // int 형 1차원 배열

    

    double_matrix = get_matrix_space<double>(2, 3);     // double 형 다차원 배열, 2 x 3

    int_matrix = get_matrix_space<int>(2, 3);          // int 형 다차원 배열, 2 x 3

        

    for (n=0;n<2;n++)

    {

        double_vector[n]=n*3.1;  // 걍 곱하기

        int_vector[n]=n*3;          // 걍 곱하기

        

        

        for (i=0;i<3;i++)

        {

            double_matrix[n][i]=n*i*3.1;   // 걍 곱하기

            int_matrix[n][i]=n*i*3;             // 걍 곱하기

     }

    }    

                

        

    // Buffer 입력된 값 확인

    

    for (n=0;n<2;n++)

    {

        printf("vector %g    %d\n",double_vector[n],int_vector[n]);

        

        for (i=0;i<3;i++)

        {            

            printf("Matrix %g    %d\n",double_matrix[n][i],int_matrix[n][i]);                    

     }

    }        

                

    free_vector(double_vector); // double vector 해제

    free_vector(int_vector); // int vector 해제

      

    

    free_matrix(double_matrix,2); // double matrix 해제

    free_matrix(int_matrix,2); // int matrix 해제

            

    return 0;

}

 




위 코드를 Geany 에서 컴파일 및 실행 하면 다음과 같은 결과가 나온다

 

 

 

C 동적 메모리 할당부터 쭉 어케 저케 오다 보니 위와 같은 C++ template까지 설명을 했다.

 



 

참고로 … C++ 에서 동적 배열 생성시에는 malloc(), calloc() 보다는 new 라는 키워드를 이용한다.

 

또한 벡터를 저렇게 template 을 만들면서 까지 쓸 필요가 없다.

C++ STL (Standard Template Library) 에 <
vector > 라는 헤더 파일이 있으니 참조하기 바란다.


전세계의 사람들은 어떤 프로그래밍 언어를 주로 이용할까에 대한 궁금함을 항상 가지고 있었다.

인터넷 검색을 통해 이런 궁금증을 해결해 줄 수 있는 사이트를 발견했다.

TIOBE 소프트웨어라는 회사의 홈페이지에는 한 달에 한번씩 프로그래밍 언어의 인기도에 대한 순위를 올려 놓는다.

아래 순위의 출처는 http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html 다.

이번 달의 프로그래밍 언어 인기도는 다음과 같다.

 

역시나 이번에도 1등은 자바다.

2~3 등을 하고 있는 C/C++ 야 뭐 워낙에 기본이 되는 프로그램 이니깐 할 말이 없고, 파이썬C#의 약진이 눈에 뜬다.

작년 까지만 해도 파이썬이 저 정도는 아니었던 것 같은데…… 요즘 진짜 많이 사용하는 프로그램 같다.

뭐 문법도 편리하고 여기 저기 안 붙는 데가 없으니 정말 좋은 언어라는 생각이 많이 든다.

파이썬 같은 스크립트 언어는 여러 모로 도움이 되니 프로그래밍을 하시는 분들은 꼭 한번 공부해 보시길

비트토렌트아나콘다 trac 같은 프로그램이 파이썬으로 만들어 졌고, 뭐 구글을 비롯해 NASA같은 데서도 많이 이용된다 하니 더 관심이 가는 언어 중에 하나다.

일단…… 파이썬은 공짜다. 뭐 리눅스 윈도 이런 거 안 가리고 잘 돌아가는 너무 좋은 언어다.

파이썬도 책 조금 보다 말았는데 이제 조금씩 다시 시작을 해야 하나 하는 생각이 든다.

 

요즘 관심을 가지고 공부하고 있는 perl 이 아직 순위권 내에 있는 게 반갑다. 뭐 Perl은 두말할 나위 없는 언어다…… 특히 텍스트 처리에 있어서는 타의 추종을 불허 하는 펄…… 너무 좋다. 그리고 코드가 무지 짧다. 가끔은 더럽기도.. ㅋㅋ

거기다 There's more than one way to do the same thing. 라는 펄의 철학도 넘~ 넘~ 멋지다. 난 저 한 줄에 꽂혀서 펄을 시작했다. 아직 많이 알지는 못하지만 언젠간 꼭 고수가 되었음 하는 게 펄이다.

 

이번 달에는 좀 특이한 게 NXT-G 라는 정말 듣고 보도 못한 프로그램이 순위 안에 올라 왔다.

좀 알아보니 National Instruments 라는 회사에서 만든 그래픽 프로그래밍 툴이란다. National Instruments 사는 너무나 유명한 labview 를 만든 회사다

정말 세상에는 너무 다양한 언어가 있고 공부할게 너무 많다.

저 리스트만 봐도 숨이 막힌다. 욕심 나는 언어들은 많은데…… 내 능력은 너무 보잘 것 없고….

Perl, Python, LISP, Ruby, Delphi 까지는 어케든 공부 하고 싶은데…… 아 ~~

ㅋㅋ 선택과 집중을 해야 하나……

 

현재 내가 밥 벌어 먹고 살게 해주고 있는 MATLAB 이 몇 등인지 살펴 봤다.

예전에 봤을 때는 20위권 안에 있었는데…… 지금은 29위로 밀려났다.

MATLAB 가격이 좀 싸지면 순위가 올라 갈라나……

50위 권의 순위에서는 Haskell , Fortran, Tcl, Labview 정도 욕심 난다.


+ Recent posts