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