ncurses(또는 curses) 는 Linux/Unix 계열의 환경에서 VT100 등의 터미널과 호환되는 윈도우형 입출력 라이브러이다. 이를 이용하면 윈도우의 임의의 위치에 출력도 하고, 임의의 위치에서 입력을 받을 수도 있다.

* 카라슈바 곱셈 참조

다음은 Linux 나 Cygwin 환경이면 gcc 로 컴파일하여 실행되는 C 소스이다.

 

/*
 * Filename: ezmult_003.c
 *
 * Compile: gcc -o ezmult_003 ezmult_003.c -lform -lncurses
 *
 * Execute: ./ezmult_003
 *
 *    Date: 2014. 1. 6. (Mon)  v0.002
 *    Date: 2014. 1. 8. (Wed)  v0.003
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <form.h>
#include <ncurses.h>

int main()
{
    int x0, y0, z0;
    int s01, s02, t0;
    int x, y, z;
    int s1, s2, t;
    int i, j;
    int flag_insert_mode = 1;
    int o1 = 0;
    int o2 = 0;
    int o3 = 0;

    FIELD *field[4];
    FORM  *my_form;
    int ch;
 
    /* curses 초기화하기 */
    initscr();
    start_color();    // 색상을 사용하려면 initscr() 호출 후 즉시 이를 호출해야 함
    nonl();            // 필드에서 엔터 키가 작용되게 하기 위함
    cbreak();
    noecho();
    keypad(stdscr, TRUE);


    srand(time(NULL));
    x = rand()/(RAND_MAX + 1.0)*90 + 10;
    y = rand()/(RAND_MAX + 1.0)*90 + 10;
    z = x*y;
    s1 = (x/10)*(y/10);
    s2 = (x%10)*(y%10);
    t = (x/10)*(y%10) + (x%10)*(y/10);
   
    if (s1 < 10)
    {
         o1 = 1;
    }
    if (t < 100)
    {
         o2 = 1;
    }
    if (z < 1000)
    {
         o3 = 1;
    }
    refresh();
    

    /* 필드 초기화 */
    field[0] = new_field(1, 4-o1,  6, 14+o1, 0, 0);
    field[1] = new_field(1, 3-o2,  7, 14+o2, 0, 0);
    field[2] = new_field(1, 4-o3,  9, 14+o3, 0, 0);
    field[3] = NULL;


    /* 폼 생성하여 붙여 넣기 */
    my_form = new_form(field);
    post_form(my_form);
    refresh();


     /* 색상 초기화 */
    init_pair(1, COLOR_WHITE, COLOR_GREEN);
    init_pair(2, COLOR_WHITE, COLOR_GREEN);
    init_pair(3, COLOR_WHITE, COLOR_GREEN);
    init_pair(4, COLOR_MAGENTA, COLOR_BLACK);
    init_pair(5, COLOR_CYAN, COLOR_BLACK); 
    init_pair(6, COLOR_WHITE, COLOR_BLACK);
    init_pair(7, COLOR_BLACK, COLOR_WHITE);


    x0 = rand()/(RAND_MAX + 1.0)*90 + 10;
    y0 = rand()/(RAND_MAX + 1.0)*90 + 10;
    z0 = x0*y0;
    s01 = (x0/10)*(y0/10);
    s02 = (x0%10)*(y0%10);
    t0 = (x0/10)*(y0%10) + (x0%10)*(y0/10);


    mvprintw(3, 4, "%4d", x0);
    mvprintw(4, 3, "x%4d", y0);
    mvprintw(5, 3, "-----");
    mvprintw(6, 4, "%2d%02d", s01, s02);
    mvprintw(7, 4, "%3d", t0);
    mvprintw(8, 3, "-----");
    mvprintw(9, 4, "%4d", z0);
    refresh();


    mvprintw(3, 14, "%4d", x);
    mvprintw(4, 13, "x%4d", y);
    mvprintw(5, 13, "-----");
    mvprintw(8, 13, "-----");
    attron(COLOR_PAIR(7));
    mvprintw(0, 0, "Ins");
    attron(COLOR_PAIR(6));
    move(6, 14);
    refresh();


    set_field_type(field[0], TYPE_INTEGER, 0, 0, 9999);
    set_field_type(field[1], TYPE_INTEGER, 0, 0, 999);
    set_field_type(field[2], TYPE_INTEGER, 0, 0, 9999);
    field_opts_on(field[0], O_EDIT);
    field_opts_on(field[1], O_EDIT);
    field_opts_on(field[2], O_EDIT);
    field_opts_on(field[0], O_ACTIVE);
    field_opts_on(field[1], O_ACTIVE);
    field_opts_on(field[2], O_ACTIVE);

 
    /* 필드 옵션 설정 */
    set_field_back(field[0], A_UNDERLINE); 
    set_field_back(field[1], A_UNDERLINE); 

    set_field_back(field[2], A_UNDERLINE); 


    /* 필드 옵션 설정 */
    set_field_fore(field[0], COLOR_PAIR(1));
    set_field_back(field[0], COLOR_PAIR(2));
    set_field_fore(field[1], COLOR_PAIR(1));

    set_field_back(field[1], COLOR_PAIR(2));
    set_field_fore(field[2], COLOR_PAIR(1));
    set_field_back(field[2], COLOR_PAIR(2));


    if (s1 >= 10)
        move(6, 14);
    else
        move(6, 15);
    refresh();


    /* 사용자 요구에 따라 번복 여부 결정 */
    while((ch = getch()) != KEY_F(1) && ch != 0x1B && ch != 0x0D)   
        switch(ch)
      {

           case KEY_DOWN:
           case KEY_ENTER:
               /* 다음 필드로 가기 */
               form_driver(my_form, REQ_NEXT_FIELD);
               break;
          case KEY_UP:
              /* 이전 필드로 가기 */
              form_driver(my_form, REQ_PREV_FIELD);
              break;
         case KEY_BACKSPACE:
         case 0x7F:
              form_driver(my_form, REQ_DEL_PREV);
              break;
         case KEY_IC:
              if (flag_insert_mode != 0)
             {
                 form_driver(my_form, REQ_OVL_MODE);
                 getyx(stdscr, j, i);
                 mvprintw(0, 0, "   ");
                 move(j, i);
                 flag_insert_mode = 0;
             }
             else
            {
                 form_driver(my_form, REQ_INS_MODE);
                 getyx(stdscr, j, i);
                attron(COLOR_PAIR(7));
                mvprintw(0, 0, "Ins");
                attron(COLOR_PAIR(6));
                move(j, i);
                flag_insert_mode = 1;
            }
            break;
        case KEY_DC:
            form_driver(my_form, REQ_DEL_CHAR);
            break;
        case KEY_LEFT:
            form_driver(my_form, REQ_LEFT_CHAR);
            break;
        case KEY_RIGHT:
            form_driver(my_form, REQ_RIGHT_CHAR);
            break;
        default:
            form_driver(my_form, ch);
            break;
       }
    }
 
    form_driver(my_form, REQ_NEXT_FIELD);
 
    attron(COLOR_PAIR(6));
    mvprintw(13, 0, "You have answered");
    if (atoi(field_buffer(field[0], 0)) == s1*100 + s2)
         attron(COLOR_PAIR(5));
    else
         attron(COLOR_PAIR(4));
    mvprintw(14, 8, "%4d", atoi(field_buffer(field[0], 0)));
    if (atoi(field_buffer(field[1], 0)) == t)
         attron(COLOR_PAIR(5));
    else
         attron(COLOR_PAIR(4));
    mvprintw(15, 8, "%3d", atoi(field_buffer(field[1], 0)));
    if (atoi(field_buffer(field[2], 0)) == z)
         attron(COLOR_PAIR(5));
    else
         attron(COLOR_PAIR(4));
    mvprintw(16, 8, "%4d", atoi(field_buffer(field[2], 0)));

    attron(COLOR_PAIR(6));
    mvprintw(13, 20, "Right answer is");
    mvprintw(14, 28, "%2d%02d", s1, s2);
    mvprintw(15, 28, "%3d", t);
    mvprintw(16, 28, "%4d", z);
    if (atoi(field_buffer(field[0], 0)) == s1*100 + s2
         && atoi(field_buffer(field[1], 0)) == t
         && atoi(field_buffer(field[2], 0)) == z)
        mvprintw(18, 0, "    Your answer is right.");
    else
        mvprintw(18, 0, "    Your answer is wrong.");
    mvprintw(21, 0, "Press any key to quit...");
    getch();
   
    /* 폼을 떼어내고 메모리를 해제한다. */
    unpost_form(my_form);
    free_form(my_form);
    free_field(field[0]);
    free_field(field[1]);
    free_field(field[2]);

    endwin();

    return 0;
}
 

 

* 실행 결과:

 


 

Posted by Scripter
,

32bit OS 에서는 int 타입과 long 타입이 다 같이 4바이트의 크기를 갖지만.

64bit OS 에서는 int 타입이 4바이트, long 타입이 8바이트의 크기를 갖는다.

그렇다면 64비트 리눅스 환경에서 32비트 용으로 작성된 C 소스를 gcc 로 컴파일하려면 어떻게 해야 할까? 

 

// Filename: testIntSize.c

int main()
{
#include <stdio.h>

int main()
{
    printf("sizeof(int) = %d\n", sizeof(int));
    printf("sizeof(long) = %d\n", sizeof(long));

    return 0;
}

 

# 64비트 용으로 컴파일하고 실행하기

$ gcc -o testIntSize testIntSize.c

$ ./testIntSize

sizeof(int) = 4
sizeof(long) = 8

 

# 32비트 용으로 컴파일하고 실행하기 (옵션 -m32 추가)

$ gcc -m32 -o testIntSize testIntSize.c

$ ./testIntSize

sizeof(int) = 4
sizeof(long) = 4

 

 

Posted by Scripter
,

 

Visual C++ 2010 으로 컴파일할 경우, 헤더파일 inttypes.h 가 Visual C++ 2010 에는 빠져 있으므로 http://msinttypes.googlecode.com/svn/trunk/inttypes.h 를 가져와서 아래의 소스와 동일한 디렉토리에 두고 컴파일한다.

char * 타입의 C 스트링으로 부터 long long 타입의 정수로 파싱하려면 C99 에서 정한 함수 strtoll 함수를 쓰면 되는데 이 함수 역시 Visual C++ 2010 에는 빠져 있으므로, _strtoi64 함수로 대체하기 위해 소스의 앞 부분에 매크로 정의 #define strtoll _strtoi64 를 추가하였다.

또 main 함수 안에서 사용된 llabs 함수는 long long 타입의 정수의 절댓값을 구하는 함수이다. abs 함수를 쓰면 절댓값이 int 타입의 값으로 나오므로 long long 타입에 대하여는 잘못된 절댓값을 가져올 수 있다.

 

* gcc 4.6.* 또는 Visual Studio 2010 의 cl 로 컴파일되는 C 소스

/*
 * Filename: eulerPhiGoodC_01.c
 *
 *  Purpose:
 *          Calculate the Euler phi function of a given nonzero integer
 *          with using its muliplicative property.
 *
 *          The Euler phi function of a given positive integer n is defined as.
 *          the number of positive integers which are relative prime to n
 *          from 1 to n.
 *
 * Compile: gcc -o eulerPhiGoodC_01 eulerPhiGoodC_01.c
 *    Or
 * Compile: cl /DVC2010 eulerPhiGoodC_01.c
 *
 * Execute: ./eulerPhiGoodC_01 [nnn]
 *    Or
 * Execute: eulerPhiGoodC_01 [nnn]
 *
 *  Date: 2011. 11.  7 (Mon)    eulerPhiGoodPython_01.py
 *  Date: 2013. 12. 13 (Fri)    eulerPhiGoodC_01.c
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#ifdef VC2010
  #include "inttypes.h"
  #define strtoll _strtoi64
#else
  #include <inttypes.h>
#endif
 
void printUsage()
{
    printf("Usage: eulerPhiGoodC_01 [nnnnnn]\n");
    printf("nnnnnn should be an integer.\n");
}

long long gcd(long long a, long long b)
{
    long long a1 = abs(a);
    long long b1 = abs(b);
    long long q = a1;
    long long r = b1;
    long long t;
    while (r != 0)
    {
        t = r;
        r = q % r;
        q = t;
    }
    return q;
}

int divide_each(long long n)
{
    long long a = 3;

    if ((n & 0x1) == 0 || n <= 1)
        return 0;
    else if (n == 2)
        return 1;

    while (a*a <= n)
    {
        if ((n % a) == 0)
            return 0;
        a += 2;
    }
    
    return 1;
}

int is_prime(long long n)
{
    return divide_each(n);
}

long long next_prime(long long n)
{
    long long k = llabs(n);
   
    k = k + 1;
    if (k <= 2)
    {
        return 2LL;
    }

    if ((k % 2) == 0 && k > 2)
        k += 1;
    while (!is_prime(k))
        k += 2;

    return k;
}


 

int main(int argc, const char *argv[])
{
    long long n = 0;
    long long cnt = 0;
    long long nphi = 0;
    long long sum = 0;
    long long t = 0;
    long long g = 1;
    long long m = 0;
    long long p = 1;
    long long *factors = (long long *)malloc(sizeof(long long)*200);
    long long nfactor = 0;
    long long ndivisor = 1;   // the number of positive divisors of the input integer
    long long nsum = 1;       // the sum of all positive divisors of the input integer
    int ndx = 0;        // index of storing position factor in factors
    long long *divisors = NULL;
    long long last_prime;
    int i, j, k;

    if (argc != 2)
    {
        printUsage();
        exit(1);
    }
    else
    {
        n = strtoll(argv[1], NULL, 10);
        n = llabs(n);
        if (n != 0)
        {
            t = n;
            k = 0;
            m = 0;  // multiplicity of prime factor
            ndivisor = 1;   // the number of positive divisors of the input integer
            nsum = 1;       // the sum of all positive divisors of the input integer
            nphi = 1;       // the numner of positive integers relative prime to the input integer
    
            p = 1;
            while (t > 1 && p*p <= n)
            {
                p = next_prime(p);
                m = 0;
                while (t % p == 0)
                {
                    t = (long long)(t / p);
                    m = m + 1;
                }

                if (m > 0)
                {
                    factors[ndx] = p;
                    ndx += 1;
                    factors[ndx] = m;
                    ndx += 1;
                    nfactor += 1;
                    ndivisor *= (m + 1);
                    nsum *= (long long)((pow(p, m+1) - 1)/(p - 1));
                    nphi *= (long long)(pow(p, m - 1)*(p - 1));
                }
            }
    

            if (is_prime(t))
            {
                m = 1;
                factors[ndx] = t;
                ndx += 1;
                factors[ndx] = m;
                ndx += 1;
                nfactor += 1;
                ndivisor *= (m + 1);
                nsum *= (long long)((pow(t, m+1) - 1)/(t - 1));
                nphi *= (long long)pow(t, m - 1)*(t - 1);
                m = 0;
            }
                
            printf("Prime factorization: %"PRId64" = ", n);
            for (i = 0 ; i < 2*nfactor; i += 2)
            {
                printf("%"PRId64"^{%"PRId64"} ", factors[i], factors[i + 1]);
            }
            printf("\n");
            printf("The number of positive divisors:  tau(%"PRId64") =  %"PRId64".\n", n, ndivisor);
            printf("The sum of all positive divisors:  sigma(%"PRId64") = %"PRId64".\n", n, nsum);
            printf("The number of positive integers relatively prime:  phi(%"PRId64") = %"PRId64"\n", n, nphi);
            if (nsum == n + 1)
                printf("The integer %"PRId64" is a prime number.\n", n);
            else
                printf("The integer %"PRId64" is not a prime number.\n", n);

            divisors = (long long *)malloc(sizeof(long long)*ndivisor);

            cnt = 0;
            ndx = 0;
            divisors[ndx] = 1;
            ndx += 1;
            cnt = 1;
            for (i = 0; i < 2*nfactor; i += 2)
            {
                p = factors[i];
                m = factors[i + 1];
                for (k = 1; k <= m; k++)
                {
                    for (j = 0; j < cnt; j++)
                    {
                        divisors[ndx] = divisors[j]*pow(p, k);
                        ndx += 1;
                    }
                }
                cnt = ndx;
            }
            printf("The positive divisors of %"PRId64" are\n", n);
            for (i = 0; i < ndivisor - 1; i++)
            {
                printf("%"PRId64", ", divisors[i]);
            }
            printf("%"PRId64".\n", divisors[ndivisor - 1]);
        }
    }
 
    free(factors);
    free(divisors);
 
    return 0;
}

 

 

실행> eulerPhiGoodC_01 240
Prime factorization: 240 = 2^{4} 3^{1} 5^{1}
The number of positive divisors:  tau(240) =  20.
The sum of all positive divisors:  sigma(240) = 744.
The number of positive integers relatively prime:  phi(240) = 64
The integer 240 is not a prime number.
The positive divisors of 240 are
1, 2, 4, 8, 16, 3, 6, 12, 24, 48, 5, 10, 20, 40, 80, 15, 30, 60, 120, 240.

실행> eulerPhiGoodC_01 24345
Prime factorization: 24345 = 3^{2} 5^{1} 541^{1}
Prime factorization: 24345 = 3^{2} 5^{1} 541^{1}
The number of positive divisors:  tau(24345) =  12.
The sum of all positive divisors:  sigma(24345) = 42276.
The number of positive integers relatively prime:  phi(24345) = 12960
The integer 24345 is not a prime number.
The positive divisors of 24345 are
1, 3, 9, 5, 15, 45, 541, 1623, 4869, 2705, 8115, 24345.

실행> eulerPhiGoodC_01 2434500
Prime factorization: 2434500 = 2^{2} 3^{2} 5^{3} 541^{1}
The number of positive divisors:  tau(2434500) =  72.
The sum of all positive divisors:  sigma(2434500) = 7694232.
The number of positive integers relatively prime:  phi(2434500) = 648000
The integer 2434500 is not a prime number.
The positive divisors of 2434500 are
1, 2, 4, 3, 6, 12, 9, 18, 36, 5, 10, 20, 15, 30, 60, 45, 90, 180, 25, 50, 100, 7
5, 150, 300, 225, 450, 900, 125, 250, 500, 375, 750, 1500, 1125, 2250, 4500, 541
, 1082, 2164, 1623, 3246, 6492, 4869, 9738, 19476, 2705, 5410, 10820, 8115, 1623
0, 32460, 24345, 48690, 97380, 13525, 27050, 54100, 40575, 81150, 162300, 121725
, 243450, 486900, 67625, 135250, 270500, 202875, 405750, 811500, 608625, 1217250
, 2434500.

실행> eulerPhiGoodC_01 481000000008
Prime factorization: 481000000008 = 2^{3} 3^{1} 11^{1} 73^{1} 24958489^{1}
The number of positive divisors:  tau(481000000008) =  64.
The sum of all positive divisors:  sigma(481000000008) = 1329788347200.
The number of positive integers relatively prime:  phi(481000000008) = 143760890
880
The integer 481000000008 is not a prime number.
The positive divisors of 481000000008 are
1, 2, 4, 8, 3, 6, 12, 24, 11, 22, 44, 88, 33, 66, 132, 264, 73, 146, 292, 584, 2
19, 438, 876, 1752, 803, 1606, 3212, 6424, 2409, 4818, 9636, 19272, 24958489, 49
916978, 99833956, 199667912, 74875467, 149750934, 299501868, 599003736, 27454337
9, 549086758, 1098173516, 2196347032, 823630137, 1647260274, 3294520548, 6589041
096, 1821969697, 3643939394, 7287878788, 14575757576, 5465909091, 10931818182, 2
1863636364, 43727272728, 20041666667, 40083333334, 80166666668, 160333333336, 60
125000001, 120250000002, 240500000004, 481000000008.

실행> eulerPhiGoodC_01 481000000009
Prime factorization: 481000000009 = 83^{1} 347^{1} 3361^{1} 4969^{1}
The number of positive divisors:  tau(481000000009) =  16.
The sum of all positive divisors:  sigma(481000000009) = 488441580480.
The number of positive integers relatively prime:  phi(481000000009) = 473599042
560
The integer 481000000009 is not a prime number.
The positive divisors of 481000000009 are
1, 83, 347, 28801, 3361, 278963, 1166267, 96800161, 4969, 412427, 1724243, 14311
2169, 16700809, 1386167147, 5795180723, 481000000009.

실행> eulerPhiGoodC_01 481000000001
Prime factorization: 481000000001 = 367^{1} 1310626703^{1}
The number of positive divisors:  tau(481000000001) =  4.
The sum of all positive divisors:  sigma(481000000001) = 482310627072.
The number of positive integers relatively prime:  phi(481000000001) = 479689372
932
The integer 481000000001 is not a prime number.
The positive divisors of 481000000001 are
1, 367, 1310626703, 481000000001.

 

 

 

Posted by Scripter
,

우선 다음 소스는 컴파일하는데는 아무 문제가 없지만 실행 결과는 전혀 엉뚱하다.

printf 함수에 사용된 %lld 포맷에 문제가 있기 때문이다.

 

/*
 * Filename: testLongLong0.c
 *
 * Compile: gcc -o testLongLong0 testLongLong0.c
 *   or
 * Compile: cl testLongLong0.c
 */

#include <stdio.h>

int main()
{
    printf("Maximum long long value is %40lld\n", 9223372036854775807LL);
    printf("Maximum long long value is %40llu\n", 9223372036854775807ULL);
    printf("Maximum long long value is %40lld\n", 9223372036854775808LL);
    printf("Maximum long long value is %40llu\n", 9223372036854775808ULL);

    return 0;
}

 

우선 다음은 32비트 윈도우 XP의 명령창에서 Visual C++ 2010 의 명령줄 컴파일러 cl 로 컴파일하여 실행한 경우이다.

컴파일> cl testLongLong0.c
Microsoft (R) 32비트 C/C++ 최적화 컴파일러 버전 16.00.40219.01(80x86)
Copyright (c) Microsoft Corporation. 모든 권리 보유.

testLongLong0.c
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:testLongLong0.exe
testLongLong0.obj

실행> testLongLong0
Maximum long long value is                      9223372036854775807
Maximum long long value is                      9223372036854775807
Maximum long long value is                     -9223372036854775808
Maximum long long value is                      9223372036854775808

 

 

그리고 다읍은 32비트 윈도우 XP의 명령창에서 MinGW 의 gcc(버잔 4.7.3) 로 컴파일하여 실행한 경우이다.

컴파일> gcc -o testLongLong0 testLongLong0.c
testLongLong0.c: In function 'main':
testLongLong0.c:15:51: warning: integer constant is so large that it is unsigned
 [enabled by default]
testLongLong0.c:15:5: warning: this decimal constant is unsigned only in ISO C90
 [enabled by default]

실행> testLongLong0
Maximum long long value is                                       -1
Maximum long long value is                               4294967295
Maximum long long value is                                        0
Maximum long long value is                                        0

 

 

* ISO C99 표준에 따라 64비트 정수를 printf 함수로 출력할 때 inttypes.h 헤터파일을 인클루드하고 PRId64, PRIu64, PRIx64, PRIX64 등을 사용한다. 예를 들면,

        printf("My value is %10"PRId64"\n", some_64_bit_expression);

이다. scanf 함수로 64비트 정수를 입력받을 때는 SCNd64, SCNu64, SCNx64, SCNX64 등을 사용한다.

아래의 소스는 gcc 로 컴파일할 때 경고는 있지만 실행시 출력은 정상이다. 

/*
 * Filename: testLongLong1.c
 *
 * Compile: gcc -o testLongLong1 testLongLong1.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main()
{
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775807L);
    printf("       uint64 value is %40" PRIu64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
Maximum int64 value is                      9223372036854775807
Maximum int64 value is                         7fffffffffffffff
Maximum int64 value is                         7FFFFFFFFFFFFFFF
       uint64 value is                      9223372036854775807
Maximum int64 value is                     -9223372036854775808
Maximum int64 value is                         8000000000000000
Maximum int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |7fffffffffffffff                        |
Maximum int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

* Visual C++ 2010 에서는 64비트 정수를 printf 함수로 출력하기 위해 PRId64, PRIu64, PRIx64, PRIX64 등을 사용하면 inttypes.h 헤더 파일을 찾을 수 없다는 에러가 난다. 이 에러를 해결하기 위해 http://msinttypes.googlecode.com/svn/trunk/inttypes.h 를 인클루드하였다.

아래의 소스는 cl 로 경고 없이 컴파일도 잘 되고 실행시 출력도 정상이다. 

/*
 * Filename: testLongLong.c
 *
 * Compile: cl testLongLong.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include <stdio.h>
#include "inttypes.h"

int main()
{
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775807L);
    printf("       uint64 value is %40" PRIu64 "\n", 9223372036854775807L);
    printf("Maximum int64 value is %40" PRId64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIx64 "\n", 9223372036854775808L);
    printf("Maximum int64 value is %40" PRIX64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808L);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
Maximum int64 value is                      9223372036854775807
Maximum int64 value is                         7fffffffffffffff
Maximum int64 value is                         7FFFFFFFFFFFFFFF
       uint64 value is                      9223372036854775807
Maximum int64 value is                     -9223372036854775808
Maximum int64 value is                         8000000000000000
Maximum int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |9223372036854775807                     |
Maximum int64 value is |7fffffffffffffff                        |
Maximum int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

* 다음 소스는 gcc 또는 cl  어느 것으로도 컴파일되고 실행결과도 같지만, gcc 로 컴파일 할 때는 인크루드 부분을

        #include <inttypes.h>

로 수정해야 한다. gcc 는 4.7.x 이상이면 컴파일되고, Visual C++ 는 2008 이상이면 컴파일된다.

그대신 Visual C++ 2008 에는 헤더파일 stdint.h 가 빠져 있으므로 http://msinttypes.googlecode.com/svn/trunk/stdint.h  에서 내려받으면 된다. Visual C++ 2010 에는 이 헤더파일이 이미 있으므로 상관 없다.

 

* gcc 로 컴파일하기:

    gcc -std=c99 -o testLongLong2 testLong2.c

또는

    gcc -o testLongLong2 testLong2.c

* cl 로 컴파일하기:

    cl testLong2.c

 

/*
 * Filename: testLongLong2.c
 *
 * Compile: gcc -o testLongLong2 testLongLong2.c
 *     or
 * Compile:cl testLongLong2.c
 *
 * See: http://en.wikipedia.org/wiki/Printf_format_string
 * See: http://msinttypes.googlecode.com/svn/trunk/inttypes.h
 * See: http://msinttypes.googlecode.com/svn/trunk/stdint.h
 * See: http://en.wikibooks.org/wiki/C_Programming/C_Reference/inttypes.h
 */

#include <stdio.h>
#include "stdint.h"      //  #include <inttypes.h>  for gcc or Visual C++ 2010
#include "inttypes.h"    //  #include <inttypes.h>  for gcc

int main()
{
    printf(" INT64_MAX = %30" PRId64 "\n", INT64_MAX);
    printf(" INT64_MAX = %30" PRIx64 "\n", INT64_MAX);
    printf("UINT64_MAX = %30" PRIu64 "\n", UINT64_MAX);
    printf("UINT64_MAX = %30" PRIx64 "\n", UINT64_MAX);
    printf("\n");

    printf("Maximum  int64 value is %40" PRId64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRIx64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRIX64 "\n", 9223372036854775807LL);
    printf("        uint64 value is %40" PRIu64 "\n", 9223372036854775807LL);
    printf("Maximum  int64 value is %40" PRId64 "\n", 9223372036854775808ULL);
    printf("Maximum  int64 value is %40" PRIx64 "\n", 9223372036854775808ULL);
    printf("Maximum  int64 value is %40" PRIX64 "\n", 9223372036854775808ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 9223372036854775808ULL);
    printf("Maximum uint64 value is %40" PRIx64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIX64 "\n", 18446744073709551615ULL);
    printf("Maximum uint64 value is %40" PRIu64 "\n", 18446744073709551615ULL);

    printf("Maximum  int64 value is |%-40" PRId64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIu64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIx64 "|\n", INT64_MAX);
    printf("Maximum  int64 value is |%-40" PRIX64 "|\n", INT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIu64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIx64 "|\n", UINT64_MAX);
    printf("Maximum uint64 value is |%-40" PRIX64 "|\n", UINT64_MAX);

    return 0;
}

/*
-----------------
  Execute Result:
-----------------
 INT64_MAX =            9223372036854775807
 INT64_MAX =               7fffffffffffffff
UINT64_MAX =           18446744073709551615
UINT64_MAX =               ffffffffffffffff

Maximum  int64 value is                      9223372036854775807
Maximum  int64 value is                         7fffffffffffffff
Maximum  int64 value is                         7FFFFFFFFFFFFFFF
        uint64 value is                      9223372036854775807
Maximum  int64 value is                     -9223372036854775808
Maximum  int64 value is                         8000000000000000
Maximum  int64 value is                         8000000000000000
Maximum uint64 value is                      9223372036854775808
Maximum uint64 value is                         ffffffffffffffff
Maximum uint64 value is                         FFFFFFFFFFFFFFFF
Maximum uint64 value is                     18446744073709551615
Maximum  int64 value is |9223372036854775807                     |
Maximum  int64 value is |9223372036854775807                     |
Maximum  int64 value is |7fffffffffffffff                        |
Maximum  int64 value is |7FFFFFFFFFFFFFFF                        |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |18446744073709551615                    |
Maximum uint64 value is |ffffffffffffffff                        |
Maximum uint64 value is |FFFFFFFFFFFFFFFF                        |
*/

 

 

 

 

Posted by Scripter
,

C/C++ 언어 프로그래밍에서 까다로운 부분 중의 하나는 획득했던(할당받았던) 메모리를 여하히 해제하느냐이다. 프로그램밍의 사소한 오류로 메모리 부족 현상이 쉽게 일어나기 때문이다.

프로그램밍의 사소한 오류로 메모리 부족 현상이 쉽게 일어나기 때문이다.

자바 언어, 파이썬 언어, C# 언어 등은 자동으로 쓰레기 수집(garbage collection)이 이루어지므로 거의 신경쓰지 않아도 되지만, C 언어는 소스 작성하는 프로그래머가 직접해야 한다.

오래 전(10여년 전)에 Hans Boehm 가 만들었던 C/C++ 언어용 쓰레기 수집기(Boehm-Demers-Weiser conservative garbage collector, 줄여사 BoehmGC 러고 부름)를 이용하여 컴파일되고 실행되는 소스이다. 이 쓰레기 수집기를 쓰면, 메모리 해제(free)를 프로그래머가 신경쓰지 않아도 된다. 그렇게 하기 위해서는 헤더 파일 추가 구문

                    #include "gc.h"     또는      #include "gc/gc.h"
        또는      #include "gc_cpp.h"     또는      #include "gc/gc_cpp.h"

가 있어야 하고,  함수 malloc(크기) 대신에 매크로 GC_MALLOC(크기) 를, 함수 realloc(포인터, 크기) 대신에 매크로 GC_REALLOC(포인터, 크기) 를 사용해야 한다. 좀 더 좋은 성능을 위해서는 GC_MALLOC_ATOMIC(크기) 과 GC_enable_incremental() 을 사용하기도 한다. GC_MALLOC_ATOMIC 은 포인터를 전혀 갖지 않은 객체에 대하여만 적용된다. 


MinGW 의 gcc 나 Visual C++ 2010 용으로 동작하는지는 아직 확인 되지는 않았으나, Cygwin에는 Hans Boehm 의 쓰레기 수집기가 이미 설치되어 있어서, Cygwin 의  g++ 4.5.3 으로 컴파일할 수 있었다.

아래의 두 소스는 워낙 오래된 것이라서 #include 부분과 using namespace 부분을 수정 또는 추가하여 현재의 컴파일러로 컴파일되게 고쳤다.

* C++ 언어용 쓰레기 수집  벤치마크 테스트 (파일명: GCBench_OGC.cpp)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

#include <new>          // #include <new.h>
#include <iostream>     // #include <iostream.h>
#include <sys/time.h>

#ifdef GC
#  include "gc.h"
#endif

using namespace std;

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0 *Node;

struct Node0 {
        Node left;
        Node right;
        int i, j;
        Node0(Node l, Node r) { left = l; right = r; }
        Node0() { left = 0; right = 0; }
#       ifndef GC
          ~Node0() { if (left) delete left; if (right) delete right; }
# endif
};

struct GCBench {

        // Nodes used by a tree of a given size
        static int TreeSize(int i) {
                return ((1 << (i + 1)) - 1);
        }

        // Number of iterations to use for a given tree depth
        static int NumIters(int i) {
                return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
        }

        // Build tree top down, assigning to older objects.
        static void Populate(int iDepth, Node thisNode) {
                if (iDepth<=0) {
                        return;
                } else {
                        iDepth--;
#   ifndef GC
                          thisNode->left  = new Node0();
                          thisNode->right = new Node0();
#   else
                          thisNode->left  = new (GC_NEW(Node0)) Node0();
                          thisNode->right = new (GC_NEW(Node0)) Node0();
#   endif
                        Populate (iDepth, thisNode->left);
                        Populate (iDepth, thisNode->right);
                }
        }

        // Build tree bottom-up
        static Node MakeTree(int iDepth) {
                if (iDepth<=0) {
#       ifndef GC
                        return new Node0();
#       else
                        return new (GC_NEW(Node0)) Node0();
#       endif
                } else {
#       ifndef GC
                        return new Node0(MakeTree(iDepth-1),
                                         MakeTree(iDepth-1));
#       else
                        return new (GC_NEW(Node0)) Node0(MakeTree(iDepth-1),
                                            MakeTree(iDepth-1));
#       endif
                }
        }

        static void PrintDiagnostics() {
#if 0
                long lFreeMemory = Runtime.getRuntime().freeMemory();
                long lTotalMemory = Runtime.getRuntime().totalMemory();

                System.out.print(" Total memory available="
                                 + lTotalMemory + " bytes");
                System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
        }

        static void TimeConstruction(int depth) {
                long    tStart, tFinish;
                int     iNumIters = NumIters(depth);
                Node    tempTree;

                cout << "Creating " << iNumIters
                     << " trees of depth " << depth << endl;
               
                tStart = currentTime();
                for (int i = 0; i < iNumIters; ++i) {
#   ifndef GC
                          tempTree = new Node0();
#   else
                          tempTree = new (GC_NEW(Node0)) Node0();
#   endif
                        Populate(depth, tempTree);
#          ifndef GC
                          delete tempTree;
#   endif
                        tempTree = 0;
                }
                tFinish = currentTime();
                cout << "\tTop down construction took "
                     << elapsedTime(tFinish - tStart) << " msec" << endl;
                    
                tStart = currentTime();
                for (int i = 0; i < iNumIters; ++i) {
                        tempTree = MakeTree(depth);
#   ifndef GC
                          delete tempTree;
#   endif
                        tempTree = 0;
                }
                tFinish = currentTime();
                cout << "\tBottom up construction took "
                     << elapsedTime(tFinish - tStart) << " msec" << endl;

        }

        void main() {
                Node    root;
                Node    longLivedTree;
                Node    tempTree;
                long    tStart, tFinish;
                long    tElapsed;

#ifdef GC
// GC_full_freq = 30;
GC_enable_incremental();
#endif
                cout << "Garbage Collector Test" << endl;
                cout << " Live storage will peak at "
                     << 2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
                        sizeof(double) * kArraySize
                     << " bytes." << endl << endl;
                cout << " Stretching memory with a binary tree of depth "
                     << kStretchTreeDepth << endl;
                PrintDiagnostics();
              
                tStart = currentTime();
               
                // Stretch the memory space quickly
                tempTree = MakeTree(kStretchTreeDepth);
#  ifndef GC
                  delete tempTree;
#  endif
                tempTree = 0;

                // Create a long lived object
                cout << " Creating a long-lived binary tree of depth "
                     << kLongLivedTreeDepth << endl;
#  ifndef GC
                  longLivedTree = new Node0();
#  else
                  longLivedTree = new (GC_NEW(Node0)) Node0();
#  endif
                Populate(kLongLivedTreeDepth, longLivedTree);

                // Create long-lived array, filling half of it
                cout << " Creating a long-lived array of "
                     << kArraySize << " doubles" << endl;
#  ifndef GC
                  double *array = new double[kArraySize];
#  else
                  double *array = (double *)
    GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#  endif
                for (int i = 0; i < kArraySize/2; ++i) {
                        array[i] = 1.0/i;
                }
                PrintDiagnostics();

                for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2)
{
                        TimeConstruction(d);
                }

                if (longLivedTree == 0 || array[1000] != 1.0/1000)
                        cout << "Failed" << endl;
                                        // fake reference to LongLivedTree
                                        // and array
                                        // to keep them from being optimized away

                tFinish = currentTime();
                tElapsed = elapsedTime(tFinish-tStart);
                PrintDiagnostics();
                cout << "Completed in " << tElapsed << " msec" << endl;
#  ifdef GC
    cout << "Completed " << GC_gc_no << " collections" <<endl;
    cout << "Heap size is " << GC_get_heap_size() << endl;
#  endif
        }
};

main () {
    GCBench x;
    x.main();
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ g++ -o GCBench GCBench.cpp -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 351 msec
        Bottom up construction took 348 msec
Creating 8256 trees of depth 6
        Top down construction took 352 msec
        Bottom up construction took 350 msec
Creating 2052 trees of depth 8
        Top down construction took 350 msec
        Bottom up construction took 350 msec
Creating 512 trees of depth 10
        Top down construction took 358 msec
        Bottom up construction took 354 msec
Creating 128 trees of depth 12
        Top down construction took 357 msec
        Bottom up construction took 355 msec
Creating 32 trees of depth 14
        Top down construction took 355 msec
        Bottom up construction took 358 msec
Creating 8 trees of depth 16
        Top down construction took 371 msec
        Bottom up construction took 373 msec
Completed in 5239 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
g++ -DGC -o GCBench GCBench.cpp -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 132 msec
        Bottom up construction took 110 msec
Creating 8256 trees of depth 6
        Top down construction took 114 msec
        Bottom up construction took 109 msec
Creating 2052 trees of depth 8
        Top down construction took 115 msec
        Bottom up construction took 112 msec
Creating 512 trees of depth 10
        Top down construction took 116 msec
        Bottom up construction took 114 msec
Creating 128 trees of depth 12
        Top down construction took 122 msec
        Bottom up construction took 116 msec
Creating 32 trees of depth 14
        Top down construction took 122 msec
        Bottom up construction took 123 msec
Creating 8 trees of depth 16
        Top down construction took 137 msec
        Bottom up construction took 114 msec
Completed in 1759 msec
Completed 229 collections
Heap size is 27652096

 

* C++ 언어용 쓰레기 수집  벤치마크 테스트 (파일명: GCBench_OGC.cpp)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

#include <new>         // #include <new.h>
#include <iostream>    // #include <iostream.h>
#include <sys/time.h>

#ifdef GC
#include "gc_cpp.h"    // #  include "gc.h"
#endif
#ifdef OGC
#  include "ogc.h"
#endif

using namespace std;

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

struct Node0 {
#       ifdef OGC
          gc_ptr<Node0> left;
          gc_ptr<Node0> right;
          Node0(gc_ptr<Node0> l, gc_ptr<Node0> r) { left = l; right = r; }
# else
          Node0 * left;
          Node0 * right;
          Node0(Node0 *l, Node0 *r) { left = l; right = r; }
# endif
        int i, j;
        Node0() { left = 0; right = 0; }
#       if !defined(GC) && !defined(OGC)
          ~Node0() { if (left) delete left; if (right) delete right; }
# endif
};

#ifdef OGC
typedef gc_ptr<Node0> Node;
#else
typedef struct Node0 *Node;
#endif

struct GCBench {

        // Nodes used by a tree of a given size
        static int TreeSize(int i) {
                return ((1 << (i + 1)) - 1);
        }

        // Number of iterations to use for a given tree depth
        static int NumIters(int i) {
                return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
        }

        // Build tree top down, assigning to older objects.
        static void Populate(int iDepth, Node thisNode) {
                if (iDepth<=0) {
                        return;
                } else {
                        iDepth--;
#   if defined(GC)
                          thisNode->left  = new (GC_NEW(Node0)) Node0();
                          thisNode->right = new (GC_NEW(Node0)) Node0();
#   elif defined(OGC)
                          thisNode->left  = gc_new Node0();
                          thisNode->right = gc_new Node0();
#   else
                          thisNode->left  = new Node0();
                          thisNode->right = new Node0();
#   endif
                        Populate (iDepth, thisNode->left);
                        Populate (iDepth, thisNode->right);
                }
        }

        // Build tree bottom-up
        static Node MakeTree(int iDepth) {
                if (iDepth<=0) {
#       if defined(GC)
                        return new (GC_NEW(Node0)) Node0();
#       elif defined(OGC)
                        return gc_new Node0();
#       else
                        return new Node0();
#       endif
                } else {
#       if defined(GC)
                        return new (GC_NEW(Node0)) Node0(MakeTree(iDepth-1),
                                            MakeTree(iDepth-1));
#       elif defined(OGC)
#   ifdef BROKEN_SMART_PTRS
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
                          return gc_new Node0(left, right);
#   else
                          return gc_new Node0(MakeTree(iDepth-1),
                                            MakeTree(iDepth-1));
#   endif
#       else
                        return new Node0(MakeTree(iDepth-1),
                                         MakeTree(iDepth-1));
#       endif
                }
        }

        static void PrintDiagnostics() {
#if 0
                long lFreeMemory = Runtime.getRuntime().freeMemory();
                long lTotalMemory = Runtime.getRuntime().totalMemory();

                System.out.print(" Total memory available="
                                 + lTotalMemory + " bytes");
                System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
        }

        static void TimeConstruction(int depth) {
                long    tStart, tFinish;
                int     iNumIters = NumIters(depth);
                Node    tempTree;

                cout << "Creating " << iNumIters
                     << " trees of depth " << depth << endl;
               
                tStart = currentTime();
                for (int i = 0; i < iNumIters; ++i) {
#   if defined(GC)
                          tempTree = new (GC_NEW(Node0)) Node0();
#   elif defined(OGC)
                          tempTree = gc_new Node0();
#   else
                          tempTree = new Node0();
#   endif
                        Populate(depth, tempTree);
#          if !defined(GC) && !defined(OGC)
                          delete tempTree;
#   endif
                        tempTree = 0;
                }
                tFinish = currentTime();
                cout << "\tTop down construction took "
                     << elapsedTime(tFinish - tStart) << " msec" << endl;
                    
                tStart = currentTime();
                for (int i = 0; i < iNumIters; ++i) {
                        tempTree = MakeTree(depth);
#   if !defined(GC) && !defined(OGC)
                          delete tempTree;
#   endif
                        tempTree = 0;
                }
                tFinish = currentTime();
                cout << "\tBottom up construction took "
                     << elapsedTime(tFinish - tStart) << " msec" << endl;

        }

        void main() {
                Node    root;
                Node    longLivedTree;
                Node    tempTree;
                long    tStart, tFinish;
                long    tElapsed;

#ifdef GC
// GC_full_freq = 30;
GC_enable_incremental();
#endif

#         ifdef OGC
    GC::SetPolicy(100);
#  endif
                cout << "Garbage Collector Test" << endl;
                cout << " Live storage will peak at "
                     << 2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
                        sizeof(double) * kArraySize
                     << " bytes." << endl << endl;
                cout << " Stretching memory with a binary tree of depth "
                     << kStretchTreeDepth << endl;
                PrintDiagnostics();
              
                tStart = currentTime();
               
                // Stretch the memory space quickly
                tempTree = MakeTree(kStretchTreeDepth);
#  if !defined(GC) && !defined(OGC)
                  delete tempTree;
#  endif
                tempTree = 0;

                // Create a long lived object
                cout << " Creating a long-lived binary tree of depth "
                     << kLongLivedTreeDepth << endl;
#  if defined(GC)
                  longLivedTree = new (GC_NEW(Node0)) Node0();
#         elif defined(OGC)
                  longLivedTree = gc_new Node0();
#  else
                  longLivedTree = new Node0();
#  endif
                Populate(kLongLivedTreeDepth, longLivedTree);

                // Create long-lived array, filling half of it
                cout << " Creating a long-lived array of "
                     << kArraySize << " doubles" << endl;
#  if defined(GC)
                  double *array = (double *)
    GC_MALLOC(sizeof(double) * kArraySize);
#  else
                  double *array = new double[kArraySize];
#  endif
                for (int i = 0; i < kArraySize/2; ++i) {
                        array[i] = 1.0/i;
                }
                PrintDiagnostics();

                for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2)
{
                        TimeConstruction(d);
                }

                if (longLivedTree == 0 || array[1000] != 1.0/1000)
                        cout << "Failed" << endl;
                                        // fake reference to LongLivedTree
                                        // and array
                                        // to keep them from being optimized away

                tFinish = currentTime();
                tElapsed = elapsedTime(tFinish-tStart);
                PrintDiagnostics();
                cout << "Completed in " << tElapsed << " msec" << endl;
#  ifdef GC
    cout << "Completed " << GC_gc_no << " collections" <<endl;
    cout << "Heap size is " << GC_get_heap_size() << endl;
#  endif
        }
};

main () {
    GCBench x;
    x.main();
}

 

* 컴파일하기
$ g++ -o GCBench GCBench_OGC.cpp -lgc

* 실행하기
$ ./GCBench_OGC
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 407 msec
        Bottom up construction took 348 msec
Creating 8256 trees of depth 6
        Top down construction took 351 msec
        Bottom up construction took 348 msec
Creating 2052 trees of depth 8
        Top down construction took 352 msec
        Bottom up construction took 347 msec
Creating 512 trees of depth 10
        Top down construction took 354 msec
        Bottom up construction took 354 msec
Creating 128 trees of depth 12
        Top down construction took 355 msec
        Bottom up construction took 356 msec
Creating 32 trees of depth 14
        Top down construction took 355 msec
        Bottom up construction took 359 msec
Creating 8 trees of depth 16
        Top down construction took 366 msec
        Bottom up construction took 374 msec
Completed in 5332 msec

 

 

 

 

Posted by Scripter
,

C 언어 프로그래밍에서 까다로운 부분 중의 하나는 획득했던(할당받았던) 메모리를 여하히 해제하느냐이다. 프로그램밍의 사소한 오류로 메모리 부족 현상이 쉽게 일어나기 때문이다.

자바 언어, 파이썬 언어, C# 언어 등은 자동으로 쓰레기 수집(garbage collection)이 이루어지므로 거의 신경쓰지 않아도 되지만, C 언어는 소스 작성하는 프로그래머가 직접해야 한다.

오래 전(10여년 전)에 Hans Boehm 가 만들었던 C/C++ 언어용 쓰레기 수집기(Boehm-Demers-Weiser conservative garbage collector, 줄여사 BoehmGC 러고 부름)를 이용하여 컴파일되고 실행되는 소스이다. 이 쓰레기 수집기를 쓰면, 메모리 해제(free)를 프로그래머가 신경쓰지 않아도 된다. 그렇게 하기 위해서는 헤더 파일 추가 구문

              #include "gc.h"     또는      #include "gc/gc.h"

가 있어야 하고,  함수 malloc(크기) 대신에 매크로 GC_MALLOC(크기) 를, 함수 realloc(포인터, 크기) 대신에 매크로 GC_REALLOC(포인터, 크기) 를 사용해야 한다. 좀 더 좋은 성능을 위해서는 GC_MALLOC_ATOMIC(크기) 과 GC_enable_incremental() 을 사용하기도 한다. GC_MALLOC_ATOMIC 은 포인터를 전혀 갖지 않은 객체에 대하여만 적용된다. 



MinGW 의 gcc 나 Visual C++ 2010 용으로 동작하는지는 아직 확인 되지는 않았으나, Cygwin에는 Hans Boehm 의 쓰레기 수집기가 이미 설치되어 있어서, Cygwin 의  gcc 4.5.3 으로 컴파일할 수 있었다.

 

/*
 * Filename: testGC_01.c 
 *
 *           Test a garbage collection for C language.
 *
 * Compile: gcc -o testGC_01 testGC_01.c -lgc
 *
 * Execute: ./testGC_01
 *
 * See: http://www.hpl.hp.com/personal/Hans_Boehm/gc/simple_example.html
 */


#include "gc.h"
#include <assert.h>
#include <stdio.h>

int main()
{
    int i;

    GC_INIT(); /* Optional on Linux/X86; see below.  */
    for (i = 0; i < 10000000; ++i)
    {
        int **p = (int **) GC_MALLOC(sizeof(int *));
        int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
        assert(*p == 0);
        *p = (int *) GC_REALLOC(q, 2 * sizeof(int));
        if (i % 100000 == 0)
            printf("Heap size = %d\n", GC_get_heap_size());
    }

    return 0;
}

 

 

실행 결과:
Heap size = 65536
Heap size = 131072
.................
.................
.................

 

 

* 단일 쓰레드에서 쓰레기 수집  벤치마크 테스트 (파일명: GCBench.c)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#ifdef GC
#  include "gc.h"
#endif

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("Creating %d trees of depth %d\n", iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\tTop down construction took %d msec\n",
               elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\tBottom up construction took %d msec\n",
               elapsedTime(tFinish - tStart));

}

int main() {
        Node    root;
        Node    longLivedTree;
        Node    tempTree;
        long    tStart, tFinish;
        long    tElapsed;
   int i, d;
 double  *array;

#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes.\n\n",
               2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
               sizeof(double) * kArraySize);
        printf(" Stretching memory with a binary tree of depth %d\n",
               kStretchTreeDepth);
        PrintDiagnostics();
# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
       
        // Stretch the memory space quickly
        tempTree = MakeTree(kStretchTreeDepth);
# ifndef GC
          destroy_Node(tempTree);
# endif
        tempTree = 0;

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }
        PrintDiagnostics();

        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }

        if (longLivedTree == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o GCBench GCBench.c -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 378 msec
        Bottom up construction took 374 msec
Creating 8256 trees of depth 6
        Top down construction took 379 msec
        Bottom up construction took 357 msec
Creating 2052 trees of depth 8
        Top down construction took 379 msec
        Bottom up construction took 354 msec
Creating 512 trees of depth 10
        Top down construction took 383 msec
        Bottom up construction took 356 msec
Creating 128 trees of depth 12
        Top down construction took 382 msec
        Bottom up construction took 363 msec
Creating 32 trees of depth 14
        Top down construction took 387 msec
        Bottom up construction took 381 msec
Creating 8 trees of depth 16
        Top down construction took 396 msec
        Bottom up construction took 400 msec
Completed in 5525 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o GCBench GCBench.c -lgc

* 실행하기
$ ./GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
Creating 33824 trees of depth 4
        Top down construction took 44 msec
        Bottom up construction took 37 msec
Creating 8256 trees of depth 6
        Top down construction took 43 msec
        Bottom up construction took 39 msec
Creating 2052 trees of depth 8
        Top down construction took 38 msec
        Bottom up construction took 38 msec
Creating 512 trees of depth 10
        Top down construction took 38 msec
        Bottom up construction took 38 msec
Creating 128 trees of depth 12
        Top down construction took 44 msec
        Bottom up construction took 38 msec
Creating 32 trees of depth 14
        Top down construction took 38 msec
        Bottom up construction took 39 msec
Creating 8 trees of depth 16
        Top down construction took 38 msec
        Bottom up construction took 52 msec
Completed in 640 msec
Completed 25 collections
Heap size is 28975104

 

* 다중 쓰레드에서 쓰레기 수집  벤치마크 테스트 (파일명: MT_GCBench.c)

// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
// Adapted to run NTHREADS client threads concurrently.  Each
// thread executes the original benchmark.  12 June 2000  by Hans Boehm.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we are aware.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  It is possible to trade memory for
//      better time performance.  This benchmark should be run in a 32 MB
//      heap, though we don't currently know how to enforce that uniformly.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>

#ifdef GC
#  ifndef LINUX_THREADS
#     define LINUX_THREADS
#  endif
#  ifndef _REENTRANT
#     define _REENTRANT
#  endif
#  ifdef LOCAL
#    define GC_REDIRECT_TO_LOCAL
#    include "gc_local_alloc.h"
#  endif
#  include "gc.h"
#endif


#ifndef NTHREADS
#   define NTHREADS 1
#endif

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("0x%x: Creating %d trees of depth %d\n", pthread_self(), iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Top down construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Bottom up construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));

}

void * run_one_test(void * arg) {
 int d;
        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }
}

int main() {
        Node    root;
        Node    longLivedTree;
        Node    tempTree;
        long    tStart, tFinish;
        long    tElapsed;
   int i;
 double  *array;

#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
#       if defined(GC) && defined(LOCAL)
   GC_thr_init();
#   endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes.\n\n",
               2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
               sizeof(double) * kArraySize);
        printf(" Stretching memory with a binary tree of depth %d\n",
               kStretchTreeDepth);
        PrintDiagnostics();
# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
       
        // Stretch the memory space quickly
        tempTree = MakeTree(kStretchTreeDepth);
# ifndef GC
          destroy_Node(tempTree);
# endif
        tempTree = 0;

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }

        {
   pthread_t thread[NTHREADS];
   for (i = 1; i < NTHREADS; ++i) {
         int code;

     if ((code = pthread_create(thread+i, 0, run_one_test, 0)) != 0) {
           fprintf(stderr, "Thread creation failed %u\n", code);
       exit(1);
     }
   }
   /* We use the main thread to run one test.  This allows */
   /* profiling to work, for example.    */
   run_one_test(0);
   for (i = 1; i < NTHREADS; ++i) {
         int code;
     if ((code = pthread_join(thread[i], 0)) != 0) {
         fprintf(stderr, "Thread join failed %u\n", code);
           }
    }
        }
        PrintDiagnostics();

        if (longLivedTree == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o MT_GCBench MT_GCBench.c -lgc

* 실행하기
$ ./MT_GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 379 msec
        0x4b0038: Bottom up construction took 353 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 380 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 379 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 382 msec
        0x4b0038: Bottom up construction took 355 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 386 msec
        0x4b0038: Bottom up construction took 361 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 383 msec
        0x4b0038: Bottom up construction took 360 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 389 msec
        0x4b0038: Bottom up construction took 373 msec
Completed in 5423 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o MT_GCBench MT_GCBench.c -lgc

* 실행하기
$ ./MT_GCBench
Garbage Collector Test
 Live storage will peak at 8194272 bytes.

 Stretching memory with a binary tree of depth 18
 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 52 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 44 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 44 msec
        0x4b0038: Bottom up construction took 38 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 51 msec
Completed in 651 msec
Completed 25 collections
Heap size is 28975104

 

 

* 다중 쓰레드에서 쓰레기 수집  벤치마크 테스트 2 (파일명: MT_GCBench2.c)

// This is version 2 of the multithreaded GC Bench.
// Heap expansion is handled differently from version 1, in an attempt
// to make scalability measurements more meaningful.  The version with
// N threads now immediately expands the heap to N*32MB.
//
// To run this with BDWGC versions 6 and later with thread local allocation,
// define GC and LOCAL.  Without thread-local allocation, define just GC.
// To run it with the University of Tokyo scalable GC,
// define SGC.  To run it with malloc and explicit deallocation, define
// none of these.  (This should also work for Hoard.)
//
// Note that defining GC or SGC removes the explicit deallocation passes,
// which seems fair.
//
// This is adapted from a benchmark written by John Ellis and Pete Kovac
// of Post Communications.
// It was modified by Hans Boehm of Silicon Graphics.
// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
// Adapted to run NTHREADS client threads concurrently.  Each
// thread executes the original benchmark.  12 June 2000  by Hans Boehm.
// Changed heap expansion rule, and made the number of threads run-time
// configurable.  25 Oct 2000 by Hans Boehm.
//
//      This is no substitute for real applications.  No actual application
//      is likely to behave in exactly this way.  However, this benchmark was
//      designed to be more representative of real applications than other
//      Java GC benchmarks of which we were aware at the time.
//      It still doesn't seem too bad for something this small.
//      It attempts to model those properties of allocation requests that
//      are important to current GC techniques.
//      It is designed to be used either to obtain a single overall performance
//      number, or to give a more detailed estimate of how collector
//      performance varies with object lifetimes.  It prints the time
//      required to allocate and collect balanced binary trees of various
//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
//      allocates roughly the same amount of memory.
//      Two data structures are kept around during the entire process, so
//      that the measured performance is representative of applications
//      that maintain some live in-memory data.  One of these is a tree
//      containing many pointers.  The other is a large array containing
//      double precision floating point numbers.  Both should be of comparable
//      size.
//
//      The results are only really meaningful together with a specification
//      of how much memory was used.  This versions of the benchmark tries
//      to preallocate a sufficiently large heap that expansion should not be
//      needed.
//
//      Unlike the original Ellis and Kovac benchmark, we do not attempt
//      measure pause times.  This facility should eventually be added back
//      in.  There are several reasons for omitting it for now.  The original
//      implementation depended on assumptions about the thread scheduler
//      that don't hold uniformly.  The results really measure both the
//      scheduler and GC.  Pause time measurements tend to not fit well with
//      current benchmark suites.  As far as we know, none of the current
//      commercial Java implementations seriously attempt to minimize GC pause
//      times.
//
//      Since this benchmark has recently been more widely used, some
//      anomalous behavious has been uncovered.  The user should be aware
//      of this:
//      1) Nearly all objects are of the same size.  This benchmark is
//         not useful for analyzing fragmentation behavior.  It is unclear
//         whether this is an issue for well-designed allocators.
//      2) Unless HOLES is defined, it tends to drop consecutively allocated
//         memory at the same time.  Many real applications do exhibit this
//         phenomenon, but probably not to this extent.  (Defining HOLES tends
//         to move the benchmark to the opposite extreme.)
//      3) It appears harder to predict object lifetimes than for most real
//         Java programs (see T. Harris, "Dynamic adptive pre-tenuring",
//         ISMM '00).

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>

#ifdef GC
#  ifndef LINUX_THREADS
#     define LINUX_THREADS
#  endif
#  ifndef _REENTRANT
#     define _REENTRANT
#  endif
#  ifdef LOCAL
#    define GC_REDIRECT_TO_LOCAL
#    include "gc_local_alloc.h"
#  endif
#  include "gc.h"
#endif
#ifdef SGC
#  include "sgc.h"
#  define GC
#  define pthread_create GC_pthread_create
#  define pthread_join GC_pthread_join
#endif

#define MAX_NTHREADS 1024

int nthreads = 0;

#ifdef PROFIL
  extern void init_profiling();
  extern dump_profile();
#endif

//  These macros were a quick hack for the Macintosh.
//
//  #define currentTime() clock()
//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)

#define currentTime() stats_rtclock()
#define elapsedTime(x) (x)

/* Get the current time in milliseconds */

unsigned
stats_rtclock( void )
{
  struct timeval t;
  struct timezone tz;

  if (gettimeofday( &t, &tz ) == -1)
    return 0;
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
}

static const int kStretchTreeDepth    = 18;      // about 16Mb
static const int kLongLivedTreeDepth  = 16;  // about 4Mb
static const int kArraySize  = 500000;  // about 4Mb
static const int kMinTreeDepth = 4;
static const int kMaxTreeDepth = 16;

typedef struct Node0_struct {
        struct Node0_struct * left;
        struct Node0_struct * right;
        int i, j;
} Node0;

#ifdef HOLES
#   define HOLE() GC_NEW(Node0);
#else
#   define HOLE()
#endif

typedef Node0 *Node;

void init_Node(Node me, Node l, Node r) {
    me -> left = l;
    me -> right = r;
}

#ifndef GC
  void destroy_Node(Node me) {
    if (me -> left) {
 destroy_Node(me -> left);
    }
    if (me -> right) {
 destroy_Node(me -> right);
    }
    free(me);
  }
#endif

// Nodes used by a tree of a given size
static int TreeSize(int i) {
        return ((1 << (i + 1)) - 1);
}

// Number of iterations to use for a given tree depth
static int NumIters(int i) {
        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
}

// Build tree top down, assigning to older objects.
static void Populate(int iDepth, Node thisNode) {
        if (iDepth<=0) {
                return;
        } else {
                iDepth--;
#  ifdef GC
                  thisNode->left  = GC_NEW(Node0); HOLE();
                  thisNode->right = GC_NEW(Node0); HOLE();
#  else
                  thisNode->left  = calloc(1, sizeof(Node0));
                  thisNode->right = calloc(1, sizeof(Node0));
#  endif
                Populate (iDepth, thisNode->left);
                Populate (iDepth, thisNode->right);
        }
}

// Build tree bottom-up
static Node MakeTree(int iDepth) {
 Node result;
        if (iDepth<=0) {
#     ifndef GC
  result = calloc(1, sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     /* result is implicitly initialized in both cases. */
     return result;
        } else {
     Node left = MakeTree(iDepth-1);
     Node right = MakeTree(iDepth-1);
#     ifndef GC
  result = malloc(sizeof(Node0));
#     else
  result = GC_NEW(Node0); HOLE();
#     endif
     init_Node(result, left, right);
     return result;
        }
}

static void PrintDiagnostics() {
#if 0
        long lFreeMemory = Runtime.getRuntime().freeMemory();
        long lTotalMemory = Runtime.getRuntime().totalMemory();

        System.out.print(" Total memory available="
                         + lTotalMemory + " bytes");
        System.out.println("  Free memory=" + lFreeMemory + " bytes");
#endif
}

static void TimeConstruction(int depth) {
        long    tStart, tFinish;
        int     iNumIters = NumIters(depth);
        Node    tempTree;
 int  i;

 printf("0x%x: Creating %d trees of depth %d\n", pthread_self(), iNumIters, depth);
       
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
#  ifndef GC
                  tempTree = calloc(1, sizeof(Node0));
#  else
                  tempTree = GC_NEW(Node0);
#  endif
                Populate(depth, tempTree);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Top down construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));
            
        tStart = currentTime();
        for (i = 0; i < iNumIters; ++i) {
                tempTree = MakeTree(depth);
#  ifndef GC
                  destroy_Node(tempTree);
#  endif
                tempTree = 0;
        }
        tFinish = currentTime();
        printf("\t0x%x: Bottom up construction took %d msec\n",
               pthread_self(), elapsedTime(tFinish - tStart));

}

void * run_one_test(void * arg) {
 int d, i;
        Node    longLivedTree;
 double  *array;
 /* size_t initial_bytes = GC_get_total_bytes(); */

        // Create a long lived object
        printf(" Creating a long-lived binary tree of depth %d\n",
               kLongLivedTreeDepth);
# ifndef GC
          longLivedTree = calloc(1, sizeof(Node0));
# else
          longLivedTree = GC_NEW(Node0);
# endif
        Populate(kLongLivedTreeDepth, longLivedTree);

        // Create long-lived array, filling half of it
 printf(" Creating a long-lived array of %d doubles\n", kArraySize);
# ifndef GC
          array = malloc(kArraySize * sizeof(double));
# else
#   ifndef NO_PTRFREE
            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
#   else
            array = GC_MALLOC(sizeof(double) * kArraySize);
#   endif
# endif
        for (i = 0; i < kArraySize/2; ++i) {
                array[i] = 1.0/i;
        }

        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
                TimeConstruction(d);
        }
 /* printf("Allocated %ld bytes before start, %ld after\n",
  initial_bytes, GC_get_total_bytes() - initial_bytes); */
        if (longLivedTree->left -> right == 0 || array[1000] != 1.0/1000)
  fprintf(stderr, "Failed\n");
                                // fake reference to LongLivedTree
                                // and array
                                // to keep them from being optimized away

}

int main(int argc, char **argv) {
        Node    root;
        Node    tempTree[MAX_NTHREADS];
        long    tStart, tFinish;
        long    tElapsed;
   int i;
# ifdef SGC
   SGC_attr_t attr;
# endif

 if (1 == argc) {
     nthreads = 1;
 } else if (2 == argc) {
     nthreads = atoi(argv[1]);
     if (nthreads < 1 || nthreads > MAX_NTHREADS) {
  fprintf(stderr, "Invalid # of threads argument\n");
  exit(1);
     }
 } else {
     fprintf(stderr, "Usage: %s [# of threads]\n");
     exit(1);
 }
#       if defined(SGC)
   /* The University of Tokyo collector needs explicit */
   /* initialization.     */
   SGC_attr_init(&attr);
   SGC_init(nthreads, &attr);
#   endif
#ifdef GC
 // GC_full_freq = 30;
 // GC_free_space_divisor = 16;
 // GC_enable_incremental();
#endif
 printf("Garbage Collector Test\n");
  printf(" Live storage will peak at %d bytes or less .\n\n",
               2 * sizeof(Node0) * nthreads
          * (TreeSize(kLongLivedTreeDepth) + TreeSize(kMaxTreeDepth))
               + sizeof(double) * kArraySize);
        PrintDiagnostics();
       
# ifdef GC
   /* GC_expand_hp fails with empty heap */
   GC_malloc(1);
   GC_expand_hp(32*1024*1024*nthreads);
# endif

# ifdef PROFIL
     init_profiling();
# endif
      
        tStart = currentTime();
        {
   pthread_t thread[MAX_NTHREADS];
   for (i = 1; i < nthreads; ++i) {
         int code;

     if ((code = pthread_create(thread+i, 0, run_one_test, 0)) != 0) {
           fprintf(stderr, "Thread creation failed %u\n", code);
       exit(1);
     }
   }
   /* We use the main thread to run one test.  This allows */
   /* profiling to work, for example.    */
   run_one_test(0);
   for (i = 1; i < nthreads; ++i) {
         int code;
     if ((code = pthread_join(thread[i], 0)) != 0) {
         fprintf(stderr, "Thread join failed %u\n", code);
           }
    }
        }
        PrintDiagnostics();

        tFinish = currentTime();
        tElapsed = elapsedTime(tFinish-tStart);
        PrintDiagnostics();
        printf("Completed in %d msec\n", tElapsed);
# ifdef GC
   printf("Completed %d collections\n", GC_gc_no);
   printf("Heap size is %d\n", GC_get_heap_size());
#       endif
# ifdef PROFIL
   dump_profile();
# endif
        return 0;
}

 

* 쓰레기 수집기가 동작하지 않도록 컴파일하기
$ gcc -o MT_GCBench2 MT_GCBench2.c -lgc

* 실행하기
$ ./MT_GCBench2
Garbage Collector Test
 Live storage will peak at 12388544 bytes or less .

 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 396 msec
        0x4b0038: Bottom up construction took 379 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 399 msec
        0x4b0038: Bottom up construction took 396 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 385 msec
        0x4b0038: Bottom up construction took 368 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 419 msec
        0x4b0038: Bottom up construction took 380 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 399 msec
        0x4b0038: Bottom up construction took 360 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 414 msec
        0x4b0038: Bottom up construction took 358 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 415 msec
        0x4b0038: Bottom up construction took 402 msec
Completed in 5504 msec

 

* 쓰레기 수집기가 동작하도록 컴파일하기
$ gcc -DGC -o MT_GCBench2 MT_GCBench2.c -lgc

* 실행하기
$ ./MT_GCBench2
Garbage Collector Test
 Live storage will peak at 12388544 bytes or less .

 Creating a long-lived binary tree of depth 16
 Creating a long-lived array of 500000 doubles
0x4b0038: Creating 33824 trees of depth 4
        0x4b0038: Top down construction took 54 msec
        0x4b0038: Bottom up construction took 41 msec
0x4b0038: Creating 8256 trees of depth 6
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 2052 trees of depth 8
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 512 trees of depth 10
        0x4b0038: Top down construction took 38 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 128 trees of depth 12
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 39 msec
0x4b0038: Creating 32 trees of depth 14
        0x4b0038: Top down construction took 39 msec
        0x4b0038: Bottom up construction took 40 msec
0x4b0038: Creating 8 trees of depth 16
        0x4b0038: Top down construction took 40 msec
        0x4b0038: Bottom up construction took 42 msec
Completed in 581 msec
Completed 14 collections
Heap size is 33619968

 

 

 

 

Posted by Scripter
,

 

다음 한 개의 C++ 소스파일 만으로 간단한 Visual C++ 2010 용 MFC 응용프로그램을 만든다.

 

// Filename: MfcHelloApp.cpp
//
//  Compile: cl /nologo /MD /W3 /EHsc /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"  /D "_AFXDLL" /D "_MBCS"  /Yc /FD /c MfcHelloApp.cpp
//
//     Link: link /nologo /subsystem:windows /incremental:no /machine:I386 /out:"MfcHelloApp.exe"  MfcHelloApp.obj
//
//  Execute: MfcHelloApp
//
//  See: %VisualStudio2010_HOME%\Samples\Mfc\general\helloapp\helloapp.cpp
//  Date: 2013. 10. 10.


#include <afxwin.h>
#include <wchar.h>
#include <cmath>

#ifdef MINIMAL

// Stub out non-critical CRT initialization functions
extern "C" void _setenvp() { }
extern "C" void _setargv() { }

// Define a window class derived from CWnd
class CHelloWindow : public CWnd
{
public:
    CHelloWindow()
    {
        CreateEx(WS_EX_CLIENTEDGE,
                      AfxRegisterWndClass(0, ::LoadCursor(NULL, IDC_ARROW),
                      (HBRUSH)(COLOR_WINDOW+1)),
                      _T("Hello World!"),
                      WS_OVERLAPPEDWINDOW,
                      CW_USEDEFAULT,
                      CW_USEDEFAULT,
                      400,       /// CW_USEDEFAULT,
                      220,       /// CW_USEDEFAULT,
                      NULL,
                      NULL,
                      0);
    }
};

#else

// Define a window class derived from CFrameWnd
class CHelloWindow : public CFrameWnd
{
public:
    CHelloWindow()
    { Create(NULL, _T("MFC, 안녕?"), WS_OVERLAPPEDWINDOW, rectDefault); }
    afx_msg void OnPaint();
    DECLARE_MESSAGE_MAP();
};

BEGIN_MESSAGE_MAP(CHelloWindow, CFrameWnd)
    ON_WM_PAINT()
END_MESSAGE_MAP()

void CHelloWindow::OnPaint() {
    CPaintDC dc(this);
    CString msg = "간단한 MFC 응용프로그램";
    dc.TextOut(10, 5, msg);
    wchar_t temp[120];
    double x, y;
    int xpos, ypos;
    x = 1.2;
    y = 5.1;
    swprintf(temp, 100, L"    합:  %wg + %wg = %wg", x, y, x + y);
    xpos = 75;
    ypos = 40;
    dc.TextOut(xpos, ypos, temp);
    swprintf(temp, 100, L"    차:  %wg - %wg = %wg", x, y, x - y);
    ypos += 20;
    dc.TextOut(xpos, ypos, temp);
    swprintf(temp, 100, L"    곱:  %wg * %wg = %wg", x, y, x * y);
    ypos += 20;
    dc.TextOut(xpos, ypos, temp);
    if (y != 0.0) {
        swprintf(temp, 100, L"    몫:  %wg / %wg = %wg", x, y, x / y);
        ypos += 20;
        dc.TextOut(xpos, ypos, temp);
    }
    if (x > 0.0) {
        swprintf(temp, 100, L"멱승:  %wg**%wg = %wg", x, y, pow(x, y));
        ypos += 20;
        dc.TextOut(xpos, ypos, temp);
    }
    if (x > 0.0 && x != 0.0 && y > 0.0) {
        swprintf(temp, 100, L"로그:  log_%wg( %wg ) = %wg", x, y, log(y)/log(x));
        ypos += 20;
        dc.TextOut(xpos, ypos, temp);
    }
}

#endif

// Define an application class derived from CWinApp
class CHelloApp : public CWinApp
{
public:
    virtual BOOL InitInstance()
    {
        m_pMainWnd = new CHelloWindow();
        m_pMainWnd->ShowWindow(m_nCmdShow);
        m_pMainWnd->SetWindowPos(NULL, 0, 0, 400, 220, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
        m_pMainWnd->UpdateWindow();
        return TRUE;
    }
};

CHelloApp HelloApp;  // HelloApp's constructor initializes and runs the app

 

* 컴파일 및 링크하기

 명령창에서 다음 컴파일 명령을 한 줄로 입력한다.

    cl /nologo /MD /W3 /EHsc /O2 /D "WIN32" /D "NDEBUG"  
        /D "_WINDOWS"  /D "_AFXDLL" /D "_MBCS"  /Yc /FD /c 
        MfcHelloApp.cpp  

 

 이어서 다음 링크 명령을 한 줄로 입력한다.

    link /nologo /subsystem:windows /incremental:no /machine:I386  
         /out:"MfcHelloApp.exe"  MfcHelloApp.obj

 

* 실행 결과

 

 

 

Posted by Scripter
,

다음 한 개의 C++ 소스파일 만으로 간단한 Visual C++ 2010 용 Win32 응용프로그램을 만든다.

 

// Filename: ExSdkApp.cpp
//
//  Compile: cl /Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D "WIN32" 
//              /D "NDEBUG" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /fp:precise 
//              /Zc:wchar_t /Zc:forScope  /Gd /analyze- /errorReport:queue  ExSdkApp.cpp 
//              kernel32.lib user32.lib gdi32.lib
//
//  Execute: ExSdkApp
//
//  See: http://msdn.microsoft.com/en-us/library/vstudio/bb384843(v=vs.100).aspx
//  Date: 2013. 10. 10.

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <cmath>
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// 전역 변수(Global variables)

// 주요 창의 클래스 명
static TCHAR szWindowClass[] = _T("win32sample");

// 애플리케이션의 주요 창의 제목
/// static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
static TCHAR szTitle[] = _T("Win32 SDK 간단 예제");

 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
    static char szAppName[] = "ExSdk";
    HWND   hwnd;
    MSG    msg;
    WNDCLASSEX  wndclass;
 
    wndclass.cbSize  = sizeof (wndclass);
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc  = WndProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance    = hInstance;
    wndclass.hIcon    = LoadIcon (NULL, IDI_APPLICATION);
    wndclass.hCursor  = LoadCursor (NULL, IDC_ARROW);
    wndclass.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName  = NULL;
    wndclass.lpszClassName = szWindowClass;
    wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
 
    RegisterClassEx( &wndclass );
 
    hwnd = CreateWindow(szWindowClass,
                  szTitle,,
                  WS_OVERLAPPEDWINDOW,
                  CW_USEDEFAULT,
                  CW_USEDEFAULT,
                  500,    /// CW_USEDEFAULT,
                  200,    /// CW_USEDEFAULT,
                  NULL,
                  NULL,
                  hInstance,
                  NULL);
 
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
 
    while (GetMessage(&msg, NULL, 0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
    HDC          hdc;
    PAINTSTRUCT  ps;
    wchar_t temp[100];
    double x, y;
    int ypos;
 
    switch (iMsg)
    {
        case WM_CREATE:
            return 0;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            wcscpy_s(temp, 100, L"SDK로 제작한 간단한 Win32 응용프로그램");
            TextOut(hdc, 10, 5, temp, _tcslen(temp));
            x = 1.2;
            y = 5.1;
            swprintf(temp, 100, L"    합:  %wg + %wg = %wg", x, y, x + y);
            ypos = 35;
            TextOut(hdc, 15, ypos, temp, _tcslen(temp));
            swprintf(temp, 100, L"    차:  %wg - %wg = %wg", x, y, x - y);
            ypos += 20;
            TextOut(hdc, 15, ypos, temp, _tcslen(temp));
            swprintf(temp, 100, L"    곱:  %wg * %wg = %wg", x, y, x * y);
            ypos += 20;
            TextOut(hdc, 15, ypos, temp, _tcslen(temp));
            if (y != 0.0) {
                swprintf(temp, 100, L"    몫:  %wg / %wg = %wg", x, y, x / y);
                ypos += 20;
                TextOut(hdc, 15, ypos, temp, _tcslen(temp));
            }
            if (x > 0.0) {
                swprintf(temp, 100, L"멱승:  %wg**%wg = %wg", x, y, pow(x, y));
                ypos += 20;
                TextOut(hdc, 15, ypos, temp, _tcslen(temp));
            }
            if (x > 0.0 && x != 0.0 && y > 0.0) {
                swprintf(temp, 100, L"로그:  log_%wg( %wg ) = %wg", x, y, log(y)/log(x));
                ypos += 20;
                TextOut(hdc, 15, ypos, temp, _tcslen(temp));
            }
            EndPaint(hwnd, &ps);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
 
    return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

 

* 컴파일하기

 명령창에서 아래의 컴파일 명령을 한 줄로 입력한다.

    cl /Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D "WIN32" 
        /D "NDEBUG" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE"
        /Gm- /EHsc /GS /Gy /fp:precise 
        /Zc:wchar_t /Zc:forScope  /Gd /analyze- /errorReport:queue
        ExSdkApp.cpp 
        kernel32.lib user32.lib gdi32.lib

 

* 실행 결과

 

 

 

 

Posted by Scripter
,

 

1. hello_a.cpp

   첫 번째 예제는 main() 함수 대신 wmain() 함수를 쓰는 예제이다.

wmain 함수의  두 번째 파라미터를 const char *argv[]) 로 하는 대신에 const wchar_t *argv[] 로 해야 하며, 인자로 받은 문자열을 부동소수점수로 변환하기 위해  _wtof(wchar_t[]) 함수를 쓰고 있으며, 한글 출력을 위해 stdio.h 의 printf() 함수를 그냥 쓰면 된다.
wchar_t[] 타입의 문자열을 prntf() 함수로 출력하기 위해서는 포매터 %s 대신 %ws 를 써야 한다.
만일 #include <iostream> 구문을 생략하면, 컴파일 시 printf(), _wtof(), pow(), log() 함수들을 찾지 못하는 에러가 난다. 
 

// Filename: hello_a.cpp
//
//  Compile: cl /EHsc hello_a.cpp
//  Execute: hello_a [number1] [number2]

#include <iostream>

int wmain(int argc, const wchar_t *argv[])
{
    for (int i = 0; i < argc; i++) {
        printf("%d: %ws\n", i, argv[i]);
    }

    if (argc == 3)
    {
        double x;
        double y;
        x = _wtof(argv[1]);
        y = _wtof(argv[2]);
        printf( "  %s: %g + %g = %g\n", "합", x, y, x + y);
        printf( "  차: %g - %g = %g\n", x, y, x - y);
        printf( "  곱: %g * %g = %g\n", x, y, x * y);
        if (y != 0.0) 
        {
            printf( "  몫: %g / %g = %g\n", x, y, x / y);
        }
        if (x > 0.0) 
        {
            printf( "멱승: %g**%g = %g\n", x, y, pow(x,y));
        }
        if (x > 0.0 && x != 1.0 && y > 0.0) 
        {
            printf( "로그: log_%g( %g ) = %g\n", x, y, log(y)/log(x));
        }
    }

    return 0;
}

 

/*
Execute & Output:
Prompt> hello_a 1.2 5.4
0: hello_a
1: 1.2
2: 5.4
  합: 1.2 + 5.4 = 6.6
  차: 1.2 - 5.4 = -4.2
  곱: 1.2 * 5.4 = 6.48
  몫: 1.2 / 5.4 = 0.222222
멱승: 1.2**5.4 = 2.67657
로그: log_1.2( 5.4 ) = 9.24959
*/

 

 

2. hello_b.cpp

   두 번째 예제는 main() 함수 대신 _tmain() 함수를 쓰는 예제이다. Visual C++ 에서 _tmain 은 의 유무에 따라 wmain() 이나 main() 으로 바꾸어주는 일종의 매크로이다.

_tmain() 함수는 두 번째 파라미터를 const wchar_t *argv[]) 로 하는 대신에 const char *argv[] 로 해야 하며, 명령줄에서 실행 시에 인자로 받은 문자열을 부동소수점수로 변환하기 위해  atof(char[]) 함수를 쓰고 있으며, 한글 출력을 위해 stdio.h 의 printf() 함수를 그냥 쓰면 된다.
char[] 타입의 문자열을 prntf() 함수로 출력하기 위해서는 포매터 %s 를 그대로 쓰면 된다.
만일 #include <iostream> 구문을 생략하면, 컴파일 시 pow(), log() 함수들을 찾지 못하는 에러가 난다. 
 

// Filename: hello_b.cpp
//
//  Compile: cl /EHsc hello_b.cpp
//  Execute: hello_b [number1] [number2]

#include <iostream>
#include <atlstr.h>   // required for  _tmain()

int _tmain(int argc, const char *argv[])
{
    for (int i = 0; i < argc; i++) {
        printf("%d: %s\n", i, argv[i]);
    }

    if (argc == 3)
    {
        double x;
        double y;
    x = atof(argv[1]);
    y = atof(argv[2]);
       printf( "  %s: %g + %g = %g\n", "합", x, y, x + y);
       printf( "  차: %g - %g = %g\n", x, y, x - y);
       printf( "  곱: %g * %g = %g\n", x, y, x * y);
        if (y != 0.0) 
        {
            printf( "  몫: %g / %g = %g\n", x, y, x / y);
        }
        if (x > 0.0) 
        {
            printf( "멱승: %g**%g = %g\n", x, y, pow(x,y));
        }
        if (x > 0.0 && x != 1.0 && y > 0.0) 
        {
            printf( "로그: log_%g( %g ) = %g\n", x, y, log(y)/log(x));
        }
    }

    return 0;
}

/*
Execute & Output:
Prompt> hello_b 1.2 5.4
0: hello_b
1: 1.2
2: 5.4
  합: 1.2 + 5.4 = 6.6
  차: 1.2 - 5.4 = -4.2
  곱: 1.2 * 5.4 = 6.48
  몫: 1.2 / 5.4 = 0.222222
멱승: 1.2**5.4 = 2.67657
로그: log_1.2( 5.4 ) = 9.24959
*/

 

 

3. hello_c.cpp

   세 번째 예제는 C 언어에서도 통하는 전형적인 소스이다.Visual C++ 에서는 stdio.h 대신 iostream 을 인클루드해도 된다.

만일 #include <iostream> 구문을 생략하면, 컴파일 시 printf(), atof(), pow(), log() 함수들을 찾지 못하는 에러가 난다. 
 

// Filename: hello_c.cpp
//
//  Compile: cl /EHsc hello_c.cpp
//  Execute: hello_c [number1] [number2]

#include <iostream>

int main(int argc, const char *argv[])
{
    for (int i = 0; i < argc; i++) {
        printf("%d: %s\n", i, argv[i]);
    }

    if (argc == 3)
    {
        double x;
        double y;
        x = atof(argv[1]);
        y = atof(argv[2]);
        printf( "  %s: %g + %g = %g\n", "합", x, y, x + y);
        printf( "  차: %g - %g = %g\n", x, y, x - y);
        printf( "  곱: %g * %g = %g\n", x, y, x * y);
        if (y != 0.0) 
        {
            printf( "  몫: %g / %g = %g\n", x, y, x / y);
        }
        if (x > 0.0) 
        {
            printf( "멱승: %g**%g = %g\n", x, y, pow(x,y));
        }
        if (x > 0.0 && x != 1.0 && y > 0.0) 
        {
            printf( "로그: log_%g( %g ) = %g\n", x, y, log(y)/log(x));
        }
    }

    return 0;
}

/*
Execute & Output:
Prompt> hello_c 1.2 5.4
0: hello_c
1: 1.2
2: 5.4
  합: 1.2 + 5.4 = 6.6
  차: 1.2 - 5.4 = -4.2
  곱: 1.2 * 5.4 = 6.48
  몫: 1.2 / 5.4 = 0.222222
멱승: 1.2**5.4 = 2.67657
로그: log_1.2( 5.4 ) = 9.24959
*/

 

 

4. hello_d.cpp

   네 번째 예제는 C 언어에서도 통하는 전형적인 소스를 조금 변형하였다. 컴솔 출력 함수 printf() 대신 wprintf() 를 사용하였다. 이 경우 문자열 상수룰 L"........" 처럼 L을 선두에 붙여 하며, 한글을 출력하기 위해서는 문자열 포맷터도 %s 대신 대문자 S를 사용한 %S 로 해야 한다. 

만일 #include <iostream> 구문을 생략하면, 컴파일 시 printf(), wprintf(), atof(), pow(), log() 함수들을 찾지 못하는 에러가 난다. 
 

// Filename: hello_d.cpp
//
//  Compile: cl /EHsc hello_d.cpp
//  Execute: hello_d [number1] [number2]

#include <iostream>

int main(int argc, const char *argv[])
{
    for (int i = 0; i < argc; i++) {
        printf("%d: %s\n", i, argv[i]);
    }

    if (argc == 3)
    {
        double x;
        double y;
        x = atof(argv[1]);
        y = atof(argv[2]);

        wprintf( L"  %S: %g + %g = %g\n", "합", x, y, x + y);
        wprintf( L"  %S: %g - %g = %g\n", "차", x, y, x - y);
        wprintf( L"  %S: %g * %g = %g\n", "곱",x, y, x * y);
        if (y != 0.0) 
        {
            wprintf( L"  %S: %g / %g = %g\n", "몫", x, y, x / y);
        }
        if (x > 0.0) 
        {
            wprintf( L"%S; %g**%g = %g\n", "멱승", x, y, pow(x,y));
        }
        if (x > 0.0 && x != 1.0 && y > 0.0) 
        {
            wprintf( L"%S; log_%g( %g ) = %g\n", "로그", x, y, log(y)/log(x));
        }
    }

    return 0;
}

/*
Execute & Output:
Prompt> hello_d 1.2 5.4
0: hello_d
1: 1.2
2: 5.4
  합: 1.2 + 5.4 = 6.6
  차: 1.2 - 5.4 = -4.2
  곱: 1.2 * 5.4 = 6.48
  몫: 1.2 / 5.4 = 0.222222
멱승; 1.2**5.4 = 2.67657
로그; log_1.2( 5.4 ) = 9.24959
*/

 

 

5. hello_e.cpp

   다섯 번째 예제는 인수 없는 main() 함수를 사용하였다. 인수가 없는 대신 #include <atlstr.h> 하고 CommandLineToArgvW() 함수를 사용하면 명령줄에서 실행 시에 넣어준 옵션 인자들을 받아 처리할 수 있다.

 여기서도 앞의 네 번째 예제 처럼, 컴솔 출력 함수 printf() 대신 wprintf() 를 사용하였다. 이 경우 문자열 상수를 표현할 때 L"........" 처럼 L을 선두에 붙여야 하며, 한글을 출력하기 위해서는 문자열 포맷터도 %s 대신 대문자 S를 사용한 %S 로 해야 한다. 

만일 #include <iostream> 구문을 생략하면, 컴파일 시 printf(), wprintf(), atof(), pow(), log() 함수들을 찾지 못하는 에러가 난다. 

 

// Filename: hello_e.cpp
//
//  Compile: cl /EHsc hello_e.cpp
//  Execute: hello_e [number1] [number2]

#include <windows.h>

#include <iostream>
#include <atlstr.h>   // for CommandLineToArgvW()

int __cdecl main()
{
    LPWSTR *szArglist;
    int nArgs;

    szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
    if ( NULL == szArglist )
    {
        wprintf(L"CommandLineToArgvW failed\n");
        return 0;
    }
    else {
        for (int i = 0; i < nArgs; i++) {
            printf("%d: %ws\n", i, szArglist[i]);
        }
    }

    if (nArgs == 3)
    {
        double x;
        double y;
        x = _wtof(szArglist[1]);
        y = _wtof(szArglist[2]);
        wprintf( L"  %S: %g + %g = %g\n", "합", x, y, x + y);
        wprintf( L"  %S: %g - %g = %g\n", "차", x, y, x - y);
        wprintf( L"  %S: %g * %g = %g\n", "곱", x, y, x * y);
        if (y != 0.0) 
        {
            wprintf( L"  %S: %g / %g = %g\n", "몫", x, y, x / y);
        }
        if (x > 0.0) 
        {
            wprintf( L"%S: %g**%g = %g\n", "멱승", x, y, pow(x,y));
        }
        if (x > 0.0 && x != 1.0 && y > 0.0) 
        {
            wprintf( L"%S: log_%g( %g ) = %g\n", "로그", x, y, log(y)/log(x));
        }
    }

    LocalFree(szArglist);

    return 0;
}

/*
Execute & Output:
Prompt> hello_e 1.2 5.4
0: hello_e
1: 1.2
2: 5.4
  합: 1.2 + 5.4 = 6.6
  차: 1.2 - 5.4 = -4.2
  곱: 1.2 * 5.4 = 6.48
  몫: 1.2 / 5.4 = 0.222222
멱승: 1.2**5.4 = 2.67657
로그: log_1.2( 5.4 ) = 9.24959
*/

 

 

6. hello_f.cpp

   여섯 번째 예제는 닷넷용 컨솔 Hello 예제이다. 컴파일 시에에 옵션 /clr 을 주어야하며, 닷넷용이므로 #include 구문은 사용하지 못하고 using 구문을 사용하여야 한다. 이 예제에서는 using namespace System; 구문을 사용하였다.

  컴솔에 출력하는 함수도 printf() 함수가 아니라 Console::WriteLine() 함수를 사용하였다. 이 경우에도 문자열 상수를 표현할 때 L"........" 처럼 L을 선두에 붙여야 한다. 

// Filename: hello_f.cpp
//
//  Compile: cl /clr hello_f.cpp
//  Execute: hello_f [number1] [number2]

using namespace System;

int main(array<System::String ^> ^args)
{
    if (args->Length == 0)
        Console::WriteLine(L"Hello, world!");
    else if (args->Length == 1)
        Console::WriteLine(L"Hello, {0}씨!", args[0]);
    else if (args->Length == 2) {
        double x = Convert::ToDouble(args[0]);
        double y = Convert::ToDouble(args[1]);
        Console::WriteLine(L"  합: {0} + {1} = {2}", x, y, x+y);
        Console::WriteLine(L"  차: {0} - {1} = {2}", x, y, x-y);
        Console::WriteLine(L"  곱: {0} * {1} = {2}", x, y, x*y);
        if (y != 0)
            Console::WriteLine(L"  몫: {0} / {1} = {2}", x, y, x/y);
        if (x > 0)
            Console::WriteLine(L"멱승: {0}**{1} = {2}", x, y, Math::Pow(x, y));
        if (x > 0 && x != 1 && y > 0)
            Console::WriteLine(L"로그: log_{0}( {1} ) = {2}", x, y, Math::Log(y)/Math::Log(x));
    }
    return 0;
}

/*
Execute & Output:
Prompt> hello_f 1.2 5.4
  합: 1.2 + 5.4 = 6.6
  차: 1.2 - 5.4 = -4.2
  곱: 1.2 * 5.4 = 6.48
  몫: 1.2 / 5.4 = 0.222222222222222
멱승: 1.2**5.4 = 2.67657075645045
로그: log_1.2( 5.4 ) = 9.24958618840702
*/

 

 

 

Posted by Scripter
,

C++98 에서는 swap 함수를 쓸려면 #include <algorithm> 을 했지만, C++0x 와 C++11 에서는 #include <utility> 로 바뀌었다.

또 빝트인 타입의 데이터를 swap 할 때는 이전 처럼 std::swap(dat1. data2) 하지만, 빌트인 타입이 아닌 데이터를 swap 할 때는 std:: 를 붙이지 않고 swap(data1, data2) 로 해야 한다.

 

Visual C++ 의 cl 로 컴파일할려면 Visual Studio 2008 이상이면 되고. g++ 로 컴파일할려면 g++ 4.5.x 이상이면 된다.

만약 Haskell Platform 에 설치된 g++ 4.5.2 로 컴파일할려면 옵션 -enable-auto-import 를 추가하면 성공작으로 컴파일될 것이다.

 

다음 소스의 컴파일과 실행을 테스트한 환경은

        Visual C++ 2008
        Visual C++ 2010
        Visual C++ 2012
        Visual C++ 2013

         gcc 4.5.2
         gcc 4.5.3
         gcc 4.6.2
         gcc 4.7.0
         gcc 4.8.0
         gcc 4.8.1

이다.

 

 

// Filename: testSwap.cpp
//
//       Test swap functions of C++98 and C++11 specifications.
//
// Compile: cl /EHsc testSwap.cpp
// Compile: g++ -std=c++11 -o testSwap testSwap.cpp
// Compile: g++ -std=c++0x -o testSwap testSwap.cpp
//
// See for detail: http://www.cplusplus.com/reference/algorithm/swap/

#include <iostream>        // std::cout
// #include <algorithm>    // std::swap since C++98
#include <utility>         // std::swap and swap since C++0x
#include <vector>          // std::vector
#include <string>          // std::string

template <typename T>
void printVector(std::vector<T> v)
{
  std::cout << '[';
  for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << " ]\n";
}


int main () {

  int x = 10, y = 20;                      // x:10 y:20
  std::swap(x, y);                         // x:20 y:10

  std::vector<int> foo (4,x), bar (6,y);   // foo:4x20 bar:6x10
  // std::swap(foo, bar);                  // foo:6x10 bar:4x20 since C++98
  swap(foo, bar);                          // foo:6x10 bar:4x20 since C++0x

  std::cout << "foo contains:";
  for (std::vector<int>::iterator it=foo.begin(); it!=foo.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';
  std::cout << '\n';

  std::string s1 = "Hello,";
  std::string s2 = "world!";
 
  std::cout << s1 << ' ' << s2 << std::endl;
  std::cout << '\n';

  std::cout << "Swapping two strings..." << std::endl;
  s1.swap(s2);
   
  std::cout << s1 << ' ' << s2 << std::endl;
  std::cout << '\n';
 
  std::vector<int> v1(10, 7);
  std::vector<int> v2(5, -1);
  std::cout << "v1 = [";
  for (std::vector<int>::iterator it = v1.begin(); it != v1.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << " ]\n";
  std::cout << "v2 = [";
  for (std::vector<int>::iterator it = v2.begin(); it != v2.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << " ]\n";
  std::cout << '\n';
 
  std::cout << "Swapping two vectors..." << std::endl;
  v1.swap(v2);

  std::cout << "v1 =";
  printVector(v1);
  std::cout << "v2 = ";
  printVector(v2);

  return 0;
}

/*
Output:
foo contains: 10 10 10 10 10 10

Hello, world!

Swapping two strings...
world! Hello,

v1 = [ 7 7 7 7 7 7 7 7 7 7 ]
v2 = [ -1 -1 -1 -1 -1 ]

Swapping two vectors...
v1 =[ -1 -1 -1 -1 -1 ]
v2 = [ 7 7 7 7 7 7 7 7 7 7 ]
*/

 

 

 

 

 

Posted by Scripter
,