일반적으로 C 언어로 작성된 함수를 C++ 언어에서 불러 사용하려면

extern "C" 라는 키워드가 필요하다.

C 언어의 함수 정의를 ****.h 라는 헤더 파일에 기록해 두고

이 헤더 파일응 C++ 소스에서 포함(include)하려면 몇 가지 주의할 점이 있다.

 

우선 함수의 정의가 있는 C  소스와 C 언어용 헤더 파일을 보자.

[(구현) 파일명: sayHello.c] ------------------------------------

#include <stdio.h>

void print_message(char *message) {
    printf("%s\n", message);
}

 

위는 print_message(char *) 라는 함수 하나만 달랑 구현되어 있는 C 소스 파일이다.

 

 

[(정의) 파일명: sayHello.h] ------------------------------------

#ifndef HELLO_H_INCLUDED
#define HELLO_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

void print_message(char *message);

#ifdef __cplusplus
}  /* end of the 'extern "C"' block */
#endif

#endif // HELLO_H_INCLUDED

 

 

위는 함수 print_message(char *) 를 다른 C 또는 C++ 소스파일에서 불러 쓸 수 있도록

그 함수의 정의를 기헉힌 헤더 파일이다. exterb "C" { ....... } 라고 힐 경우

......... 부분이 C 언어 양식이고 이를 C++ 에서 인식할 수 있도록 하는 키워드가 extern "C" 이다.

그러나 헤더 파일에 이렇게만 적어 두면 C++ 소스에서는 불러 올 순,ㄴ 있지만, C 소스에서는

불러오지 못하는 문제사 생긴다. 이를 해경하기 위해 (즉, C 소스나 C++ 소스에서 이를 불러 쓰기 위해

추가한 것이 그 위와 아래에 적어 준 

#ifdef __cplusplus
extern "C" {
#endif

...............................................

#ifdef __cplusplus
}  /* end of the 'extern "C"' block */
#endif

부분이다.

그리고 이 헤더 파일의 시작과 끝 부분에 적어 준

#ifndef HELLO_H_INCLUDED
#define HELLO_H_INCLUDED

............................................

#endif // HELLO_H_INCLUDED

부분은 이 헤더 파일이 다른 소스에 포함(include)될 경우 단 한번 만 포함되게 하는 구문이다.

 

 

 

[파일명: hello.hpp] -------------------------------------

#ifndef HELLO_HPP_INCLUDED
#define HELLO_HPP_INCLUDED

#include "sayHello.h"

#endif // HELLO_HPP_INCLUDED

 

 

위는 C++ 소소에서 포함할 헤더 파일이다.

 

 

[파일명: callSayHello.cpp] -----------------------------------

// Filename: callSayHello.cpp
//
// Compile & Link: g++ -o callSayHello callSayHello.cpp sayHello.o
// Execute: ./callSayHello
// Output:
//     Hello world!
//     Hello world!
//
//   Or
//
// Compile: cl /c sayHello.c
// Compile & Link: cl callSayHello.cpp sayHello.c /EHsc
// Execute: .\callSayHello

// Date: 2021.01.07
//

#include <iostream>
#include "hello.hpp"

using namespace std;

int main() 
{
    cout << "Hello world!" << endl;

    // print_message ("Hello world!");
    print_message ((char *)"Hello world!");
    
    return 0; 
}

 

위는 C 언어로 작성된 함수 print_message(char *) 를 불러 사용하는 C++ 소스의 내용이다.

참고로 27째 줄 // print_message ("Hello world!"); 의 주석문 표시 // 를 제거하면,

아래와 같은 컴파일 경고(warning)가 뜬다. 이 경고가 뜨더라도 컴파일되고 실행도 되지만,

그 아래 줄 처럼 (char *) 라는 캐스팅을 추가하면 경고 없이 컴파일도 잘 되고 실행도 잘 된다.

 

$ g++ -o callSayHello callSayHello.cpp sayHello.o
callSayHello.cpp: In function 'int main()':
callSayHello.cpp:27:20: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
   27 |     print_message ("Hello world!");

 

Posted by Scripter

댓글을 달아 주세요

Cygwin 에서는 printf 와 wprint 를 동시에 사용하는 경우, 컴파일은 성공하지만 실행하면 wprintf 가 제대로 동작하지 않는다.  그리고 wprint 나 swptinf 사용 시 스트링을 출력하기 위해서는 %s 대신 %ls 포맷을 사용해야 한다.

Cygwin 의 경우 wchar_t 의 크기는 2바이트이다.

C++ 언어에서는 스트링(문자열) 클래스인 string 이 준비되어 있지만, utf-8  스트링을 db위해서는 wstring 을 써야 한다. 또 표준 입출력 cin 과 cout 대신 wcin 과 wcout 을 써야 허며 이를 위해서는  헤더 파일 iostream 을 인클루드(포함)해야 하고 이름 공간 std 를 써야 한다. 또 C 언어 처럼 setlocale(LC_ALL,""); 도 해야 한다. 헤더 파일 locale.h 는 포함하지 않아도 된다.

http://blog.naver.com/PostView.nhn?blogId=manhwamani&logNo=10083589211 도 참조한다.

#include <iostream>
// #include <cwchar>
// #include <string>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
// #include <locale.h>

int main(int argc, const char *argv[]) {
    wchar_t wt[100];
    std::wstring ws;

    /// setlocale(LC_ALL,"kr_KR.UTF-8");
    setlocale(LC_ALL,"");
    // printf("sizeof(wchar_t) = %d\n", sizeof(wchar_t));
    // printf("For more informations, \nsee: http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm\n");

    std::wcout << L"sizeof(wchar_t) = " << sizeof(wchar_t) << std::endl;
    std::wcout << L"For more informations, \nsee: http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm" << std::endl;

    std::wcout << L"\n";
    wcscpy(wt, L"abc 가나다");
    std::wcout << L"Using wchar_t[],\n";
    std::wcout << wt << std::endl;
    swprintf(wt, wcslen(L"abc 가나다") + 1, L"%ls", L"abc 가나다");
    std::wcout << wt << std::endl;
    std::wcout << L"The length of \"" << wt << L"\" is " << wcslen(wt) << L"." <<  std::endl;
    wprintf(L"%ls\n", L"abc 가나다");
    std::wcout << L"\n";
    ws = L"abc 가나다";
    std::wcout << L"Using wstring,\n";
    std::wcout << ws << std::endl;
    std::wcout << L"The length of \"" << ws << L"\" is " << ws.length() << L"." <<  std::endl;
    std::wcout << L"abc 가나다" << std::endl;

    return 0;
}

 

컴파일:

$ g++ -o testWstring_02 testWstring_02.cpp

실행:

./testWstring_02
sizeof(wchar_t) = 2
For more informations,
see: http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm

Using wchar_t[],
abc 가나다
abc 가나다
The length of "abc 가나다" is 7.
abc 가나다

Using wstring,
abc 가나다
The length of "abc 가나다" is 7.
abc 가나다

 

 

 

 

Posted by Scripter

댓글을 달아 주세요

locale을 적용하지 않은 경우:

#include <iostream>
#include <string>
#include <algorithm>
 
int main()
{
  std::string s;
  std::getline(std::cin, s);
  std::reverse(s.begin(), s.end()); // modifies s
  std::cout << s << std::endl;
  return 0;
}

 

컴파일:

$ g++ -o testReverseUTF8_003 testReverseUTF8_003.cpp

실행:

$ ./testReverseUTF8_003
안녕하세요?
?▒▒츄옕핅눕▒

 

locale을 적용하고 wstring, wcout, wcin을 사용한 경우:

#include <iostream>
#include <string>
#include <algorithm>
 
int main()
{
  std::setlocale(LC_ALL, "ko_KR.UTF-8");
  std::wstring s;
  std::getline(std::wcin, s);
  std::reverse(s.begin(), s.end()); // modifies s
  std::wcout << s << std::endl;
  return 0;
}

 

컴파일:

$ g++ -o testReverseUTF8_003 testReverseUTF8_003.cpp

실행:

$ ./testReverseUTF8_003
안녕하세요?
?요세하녕안


 

 

 

Posted by Scripter

댓글을 달아 주세요

다음은 utf-8 인코딩으로 저장한 C++ 소스이다.

Cygwin의 g++ tkdyd tl,  만일  아래의 소스에서
        std::setlocale(LC_ALL, "ko_KR.UTF-8");
대신  
        std::locale::global (std::locale ("ko_KR.UTF-8"));
로 하면 캄핑ㄹ은 되지만 실행 시에

        Segmentation fault (core dumped)

에러가 난다.

* 소스 파일명: testLocale_003.cpp

// Filename: testLocale_003.cpp
//
// Compile:  g++ -std=c++11 -o testLocale_003 testLocale_003.cpp
//    or         g++ -std=c++0x -o testLocale_003 testLocale_003.cpp
//    or         g++ -o testLocale_003 testLocale_003.cpp

#include <iostream>
#include <locale>
#include <cstring>   // for strlen()

using namespace std;

int main() {
  //// std::locale::global (std::locale ("ko_KR.UTF-8"));
  std::setlocale(LC_ALL, "en_US.UTF-8");
  wcout << L"한글\n";
  wcout << wcslen(L"한글") << L"\n";
  wcout << L"韓國語\n";
  wcout << wcslen(L"韓國語") << L"\n";

  cout << u8"한글\n";
  cout << strlen(u8"한글") << "\n";
  cout << u8"韓國語\n";
  cout << strlen(u8"韓國語") << "\n";
}

 

위의 소스에서 처럼 u8"스트링" 구문을 사용하면, g++ 명령으로 컴파일 시에 -std=c++11 또는 -std=gnu11 옵션을 주어야 한다.

 

* 컴파일

$ gcc -std=c++11 -o testLocale_003 testLocale_003.cpp

* 실행

$ ./testLocale_003

한글
2
韓國語
3
한글
6
韓國語
9

 

Posted by Scripter

댓글을 달아 주세요

* Qt 5.2.1 내려받기  (아래의 예는 Visual Studio 2010 용을 받아서 설치한 경우이다. Qt Creator 3.0.1 은 자동으로 함께 설치된다,)

 

Qt Creator 를 시작한 후 메뉴에서

         File --> New File or Project...

를 택한다. 그리고 New 창에서 다음 그림에서와 같이

        Applications --> Qt Quick Application

을 택하고 "Choose..." 버튼을 클릭한다.

 

이어 나타나는 New Qt qUICK aPPLICATION 창에서 애플리케이션이 생성될 폴더와 이름을 정한다. 원하는 폴더거 없는 경우 그 우측의 "Browse" 버튼을 클릭하여 생성하거나 선택한다.

 

다음 창에서는 Qt Quick Componenet Set 을 정한다. Qt 5.0 이상은 "Qt Quick 2.0" 으ㅜㄹ 택한다.

 

다음 창에서는 Kit Selection 을 설정한다. (이 예에서는 Visual C 2010 용으로 설치한 경우이다.)

 

다음 창에서는 Project Management 를 확인한다. 앞으로 main.qml 파일만 수정하고 저장한 후 실행하면 된다. (실행 버튼만 누르면 빌드는 저절로 된다.)

 

 

* main.cpp 의 내용 (자동으로 생성된 후 수정되지 않음)

 

#include <QtGui/QGuiApplication>

#include "qtquick2applicationviewer.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/ThirdHelloQtQuickApp/main.qml"));
    viewer.showExpanded();

    return app.exec();
}
 

 

* main.qml 의 내용 (자동 생성된 main.qml 파일의 내용을 아래 처럼 수정한다.)

import QtQuick 2.0

Rectangle {
    id: page
    width: 320; height: 160
    color: "lightgray"

    Text {
        id: helloText
        text: "Hello, world!<br /><br />안녕하세요?"
        y: 25
        anchors.horizontalCenter: page.horizontalCenter
        font.pointSize: 24; font.bold: true; font.italic: true
    }
}

 

 

* Releae/Debug 변경하기 그리고 실행하기 (Qt Creator 창의 좌측 아래 부분)

 

 

* Release 배포를 위해 PATH 에 지정된 폴더에 꼭 있어야 하는 파일들:

icudt51.dll
icuin51.dll
icuuc51.dll
libEGL.dll
libGLESv2.dll
Qt5Core.dll
Qt5Gui.dll
Qt5Network.dll
Qt5Qml.dll
Qt5Quick.dll
ThirdHelloQtQuickApp.exe
 
 

 

* 만일 PATH 로 지정된 경로에 libEGL.dll 이 없으면 다음 에러 메시지 창이 뜬다.

 

 

 

* 실행 결과:

 

 

 

 

 

Posted by Scripter

댓글을 달아 주세요

SymbolicC++  는 GiNaC 처럼 심볼 처리 수학식 계산을 지원하지만, 리눅스 계열 뿐만 아니라 윈도우 환경에서도 Visual C++ 나 MinGW 의 g++ 와 함께 사용할 수 있는 수학 심볼 처리 라이브러리이다.

 

* SymbolicC++  내려받기

* Wikipedia 에서 설명하는 SymbolicC++

 

* MinGW 의 g++ 를 위한 SymbolicC++  라이브러리 만들기

모든 작업은 MinGW\msys\1.0 폴더에 있는 msys.bat 파일을 실행하여 msys 창에서 한다.

$ ./configure

$ make

$ make install

$ make clean

생성된 라이브러리 파일 libsymbolicc++.a 와 libsymbolicc++.la 는 /usr/local/lib 폴더에 존재하고, 헤더 파일 symbolicc++.h 는 /usr/local/include 폴더에 존재한다.

 

* 간단한 인터프리터 소스

/*
    SymbolicC++ : An object oriented computer algebra system written in C++

    Copyright (C) 2008 Yorick Hardy and Willi-Hans Steeb

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


// interpreter.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <cstdlib>
#include <cmath>
#include "symbolicc++.h"
using namespace std;

double error(string s)
{ cerr << "Error: " << s << ", using 0." << endl; return 0.0; }

class token
{
  private:
   int is_value;
   Symbolic v;
   string t;
   static map<string,Symbolic> values;
  public:
   token() : is_value(0), v(0), t("") {};
   token(const Symbolic &s) : is_value(1), v(s), t("") {};
   token(const string &s) : is_value(0), v(0), t(s)  {};
   Symbolic value();
   string name() { return t; }
   int isvalue() { return is_value; }
   Symbolic set(const Symbolic &d) { return values[t]=d; }
   int operator==(string s) { return (!is_value) && (t == s); }
   friend ostream& operator << (ostream&,token);
};

map<string,Symbolic> token::values;

Symbolic token::value()
{
  if(is_value) return v;
  char *end;
  int vali=(int)strtol(t.c_str(),&end,10);
  if(*end == '\0') return Symbolic(vali);
  double vald=strtod(t.c_str(),&end);
  if(*end == '\0') return Symbolic(vald);
  if(values.count(t)>0) return values[t];
  return Symbolic(t);
}

ostream& operator << (ostream& o,token t)
{ if(t.is_value) o << t.v; else o << t.t; return o;}

vector<token>
get_tokens(string s,string separator[],string ignore[])
{
  int i = 0, j, istoken = 0;
  vector<token> v;
  string value = "";
  while(i<(int)s.length())
  {
   istoken = 0;
   for(j=0;ignore[j] != "" && i<(int)s.length();j++)
    if(s.substr(i,ignore[j].length()) == ignore[j])
     i += ignore[j].length(), j = -1, istoken = 1;
   for(j=0;separator[j] != "" && !istoken;j++)
    if(s.substr(i,separator[j].length()) == separator[j])
    {
     if(value != "") { v.push_back(token(value)); value = ""; }
     v.push_back(token(separator[j]));
     i += separator[j].length();
     istoken = 1;
    }
   if(!istoken) value += s[i++];
   else if(value!="") { v.push_back(token(value)); value = ""; }
  }
  if(value != "") v.push_back(token(value));
  return v;
}

Symbolic spow(const Symbolic &x,const Symbolic &y) { return (x^y); }
Symbolic smul(const Symbolic &x,const Symbolic &y) { return x*y;   }
Symbolic sdiv(const Symbolic &x,const Symbolic &y) { return x/y;   }
Symbolic sadd(const Symbolic &x,const Symbolic &y) { return x+y;   }
Symbolic ssub(const Symbolic &x,const Symbolic &y) { return x-y;   }

Symbolic ssqrt(const vector<Symbolic> &x)  { return sqrt(x[0]);           }
Symbolic scos(const vector<Symbolic> &x)   { return cos(x[0]);            }
Symbolic ssin(const vector<Symbolic> &x)   { return sin(x[0]);            }
Symbolic stan(const vector<Symbolic> &x)   { return tan(x[0]);            }
Symbolic sexp(const vector<Symbolic> &x)   { return exp(x[0]);            }
Symbolic sln(const vector<Symbolic> &x)    { return ln(x[0]);             }
Symbolic slog(const vector<Symbolic> &x)   { return log(x[0],x[1]);       }
Symbolic sdf(const vector<Symbolic> &x)    { return df(x[0],x[1]);        }
Symbolic ssubst(const vector<Symbolic> &x) { return x[0].subst(x[1],x[2]);}
Symbolic sfunc(const vector<Symbolic> &x)  { return x[0][x[1]];           }

Symbolic evaluate(token t);

struct function {
 string name;
 int    args;
 Symbolic (*impl)(const vector<Symbolic>&);
};

Symbolic evaluate_tokens(vector<token> v)
{
  vector<token> v2, v3;
  int parenthesis, i, j, k;
  // function names, arity, and their implementation
  function functions[] = {
   { "sqrt",     1, ssqrt  },
   { "cos",      1, scos   },
   { "sin",      1, ssin   },
   { "tan",      1, stan   },
   { "exp",      1, sexp   },
   { "ln",       1, sln    },
   { "log",      2, slog   },
   { "df",       2, sdf    },
   { "subst",    3, ssubst },
   { "function", 2, sfunc  },
   { "" } };

  // default left operands for binary operators
  double initleft[] = { 1.0, 1.0, 0.0 };
  // binary operators and their implementation
  string opnames[][4] = { { "^", "" }, { "*", "/", "" }, { "+", "-", "" } };
  Symbolic (*opimpl[][3])(const Symbolic&,const Symbolic&) =
     { { spow }, { smul, sdiv }, { sadd, ssub } };

  // check for the assignment statement
  if(v.size()>2 && v[1] == "=") {
    for(j=2;j<(int)v.size();j++) v2.push_back(v[j]);
    return v[0].set(evaluate_tokens(v2));
  }

  // evaluate parenthesis first
  for(j=0;j<(int)v.size();j++)
  {
   if(v[j] == ")") return error("unbalanced parenthesis");
   else if(v[j] == "(")
   {
    for(parenthesis=1,j++;parenthesis && j<(int)v.size();j++)
    {
     if(v[j] == "(") parenthesis++;
     if(v[j] == ")") parenthesis--;
     // artificially end the parenthesized expression
     if(v[j] == "," && parenthesis == 1)
     {
      v2.push_back(token(evaluate_tokens(v3)));
      v3.clear();
     }
     else if(parenthesis) v3.push_back(v[j]);
    }
    if(parenthesis) return error("unbalanced parenthesis");
    v2.push_back(token(evaluate_tokens(v3)));
    v3.clear(); j--;
   }
   else v2.push_back(v[j]);
  }

  // evaluate functions
  for(j=0,v.clear();j<(int)v2.size();j++)
  {
   for(i=0;functions[i].name!="";i++)
   if(v2[j] == functions[i].name)
   {
    if(j+functions[i].args<(int)v2.size())
    {
      vector<Symbolic> args;
      for(k=1;k<=functions[i].args;k++)
       args.push_back(evaluate(v2[j+k]));
      v.push_back(token(functions[i].impl(args)));
      j+=functions[i].args;
    }
    else return error(functions[i].name           +
                      " without "                 +
                      char('0'+functions[i].args) +
                      " arguments");
    break;
   }
   if(functions[i].name=="") v.push_back(v2[j]);
  }
  // evaluate operators in order of precedence
  for(k=0,v2.clear();k<3;k++,v = v2,v2.clear())
  {
   token left(initleft[k]);
   for(j=0;j<(int)v.size();j++)
   {
    for(i=0;opnames[k][i]!="";i++)
    if(v[j] == opnames[k][i])
    {
     if(v2.size()) v2.pop_back();
     if(j+1<(int)v.size())
      v2.push_back(token(opimpl[k][i](evaluate(left),
                                      evaluate(v[++j]))));
     else return error(opnames[k][i]+" without second argument");
     break;
    }
    if(opnames[k][i]=="") v2.push_back(v[j]);
    left = v2.back();
   }
  }
  // check that evaluation gave a single result
  if(v.size() != 1)
  {
   for(j=0;j<(int)v.size();j++)
    cerr << "token " << j+1 << " : " << v[j] << endl;
   return error("could not evaluate expression");
  }
  return v[0].value();
}

Symbolic evaluate(token t)
{ vector<token> v; v.push_back(t); return evaluate_tokens(v); }

Symbolic evaluateformula(istream &s)
{
  char c;
  string expression;
  static string ws[] = { " ", "\t", "\n", "\r", "" };
  static string separator[] = { "=", "+", "-", "*", "/",
                                "^", "(", ")", ",", "" };
  do if((c = s.get()) != ';' && !s.eof()) expression += c;
  while(c != ';' && !s.eof());
  if(c != ';') return error("formula not terminated");
  vector<token> v = get_tokens(expression,separator,ws);
  return evaluate_tokens(v);
}

int main(void)
{
  while(!cin.eof())
  cout << " -> " << evaluateformula(cin) << endl;
  return 0;
}

 

* 컴파일 및 실행 (인터프리터를 실행하면 세미콜론(;)으로 끝나는 구문을 계산해준다.)

$ g++ -o interpreter interpreter.cpp -lsymbolicc++

$ ./interpreter
(x - 1)^3;
 -> x^(3)-3*x^(2)+3*x-1
2^3 - 2*3 + 5;
 -> 7
(x^2 - x + 1)*(x^2 + x + 1) ;
 -> x^(4)+x^(2)+1
2^10;
 -> 1024


 

Posted by Scripter

댓글을 달아 주세요

SymbolicC++  는 GiNaC 처럼 심볼 처리 수학식 계산을 지원하지만, 리눅스 계열 뿐만 아니라 윈도우 환경에서도 Visual C++ 나 MinGW 의 g++ 와 함께 사용할 수 있는 수학 심볼 처리 라이브러리이다.

 

* SymbolicC++  내려받기

* Wikipedia 에서 설명하는 SymbolicC++

 

* Visual C++ 를 위한 SymbolicC++  라이브러리 만들기

Visual Studio 에서 솔루션 파일 SymbolicC++3.sin 을 열고 아래 그림 처럼 메뉴 탭에서 Dynamic 이라고 설정된 곳을 Static 으로 변경하고 빌드한다.

그러면 에러와 경고가 몇 개 쏟아질 것이다.

 

* 에러 해결하기

SymbolicC++ 를 빌드하는 과정에서 C:\Program Files (x86)\Microsoft Visual Studio 10\VC\include 폴더에 있는 파일 xlocmon 410 째 줄에서 에러가 걸린다. 이 줄을

                 _Str2 += '-', ++_Off;   ------>    _Str2 += '-'; ++_Off;

처럼 수정(즉 콤마를 세미콜론으로 수정)하여 다시 저장한다.

그러면 에러는 해결되고 경고(warning) 몇 개가 남는다.

 

* 몇 가지 경고(warning) 해결하기

1) SymbolicC++ 의 소스 파일 중에 integrate.cpp 파일에서 "변수 se 가 선언되었지만 사용되지 않았다"는 경고가 몇 곳 나온다.  이런 경고를 해결하려면, integrate.cpp 파일에서

        } catch(const SymbolicError &se) {}

처럼 된 중을 모두 찾아

        } catch(const SymbolicError &se) { std::cout << se.message() << std::endl; }

처럼 수정하고, 이 파일의 선두 부분에 include 문

        #include <iostream>

을 추가한다..

 

2) equation.cpp 파일의 95 째 줄

        { return lhs.compare(rhs); }


        { return (lhs.compare(rhs) == 0) ? false : true; }

로 수정한다.

 

3) sum.cpp 파일의 373 째 줄

        if(j != matchpart.end()); matchpart.erase(j);


         (j != matchpart.end()) matchpart.erase(j);

로 수정한다. (세미콜론 하나 제거)

 

* SymbolicC++ 를 이용하는 간단한 부정적분 예제

/*
    SymbolicC++ : An object oriented computer algebra system written in C++

    Copyright (C) 2008 Yorick Hardy and Willi-Hans Steeb

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


// integration.cpp

#include <iostream>
#include "symbolicc++.h"
using namespace std;

int main(void)
{
  Symbolic x("x"), c("c"), z("z"), y;

  z = z[x];
  y = (1-x)*(1-x)+cos(x)+x*exp(x)+c+z;

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

  for(int i=0;i<3;i++)
  {
   y = integrate(y,x);
   y = y[integrate(x*exp(x),x) == x*exp(x) - exp(x)];
   cout << "y = " << y << endl;
  }

  return 0;
}

 

 

* 위의 예제 소스 컴파일하기 (컴파일 옵션 /MD 가 중요)

프롬프트> cl /EHsc /I SymbolicC++3-3.35-vc\include integration.cpp SymbolicC++3.lib /MD

 

* 실행하기

프롬프트> integration
y = x^(2)-2*x+cos(x)+x*e^x+c+z[x]+1
y = 1/3*x^(3)-x^(2)+sin(x)+x*e^x-e^x+c*x+int(z[x],x)+x
y = 1/12*x^(4)-1/3*x^(3)-cos(x)+x*e^x-2*e^x+1/2*c*x^(2)+int(z[x],x,x)+1/2*x^(2)
y = 1/60*x^(5)-1/12*x^(4)-sin(x)+x*e^x-3*e^x+1/6*c*x^(3)+int(z[x],x,x,x)+1/6*x^(3)

 

 

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++ 소스파일 만으로 간단한 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

댓글을 달아 주세요