'0x0001 > C, C++' 카테고리의 다른 글
[C, C++] 매크로함수 VS 인라인함수 (0) | 2019.02.09 |
---|---|
[C언어] 주석 TIP (0) | 2019.02.09 |
[C언어] n 에서 m 까지의 합을 재귀로 작정 (0) | 2019.02.09 |
[C++] Vector와 List의 차이점 (0) | 2019.02.08 |
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
[C, C++] 매크로함수 VS 인라인함수 (0) | 2019.02.09 |
---|---|
[C언어] 주석 TIP (0) | 2019.02.09 |
[C언어] n 에서 m 까지의 합을 재귀로 작정 (0) | 2019.02.09 |
[C++] Vector와 List의 차이점 (0) | 2019.02.08 |
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
Effective C++에서 본 내용인데 우연히 인터넷속에서 또 보게 되었다..
책에서 볼 땐 별로 와 닿지 않았었지만,
이렇게 충분한(?) 예제를 보니깐, 다시한번 마음에 와 닿는다.
//1. 매크로
01: #include
02: #define MAX(a,b) (a>b? a:b)
03:
04: void main()
05: {
06: int x=20, y=80,r;
07: r= max(x++,y++);
08: cout << "x= " << x << "y= " << y << "r= "<< r << endl;
09: }
결과 x=21 y=82 r=81
//2. 인라인
01: #include
02: inline int max(int a, int b) { return(a>b? a:b); }
03:
04: void main()
05: {
06: int x=20, y=80, r;
07: r=max(x++,y++);
08: cout<< "x= "<< x << "y= " << y << "r= " << r;
09: }
결과 x=21 y=81 r=80
------------------------<<설명선>>------------------------
매크로함수의 홰궤한 결과가 보이는가?
위의 결과는 왜그럴까? 사실 매크로함수와 인라인함수의 컴파일처리과정만 알면 무지무지 간단한 이야기이다.
< 실행파일이 만들어지는 4 단계 >
1) 코딩(coding)
2) 전처리기(Preprocessor)에서의 전처리(preprocessing)
3) 컴파일러(Compiler)에서의 컴파일링(compiling)
4) 링커(Linker)에 의한 링킹(linking)
사실 Tool에서 코딩하고 그냥 컴파일만 시키면 2)~4)작업은 한꺼번에 이루어지며 실행파일이 생성된다. 그렇다고 2)랑 3)작업단계의 차이를 무시하면 위와같은 실행결과의 차이를 가져온다는 말이다.
매크로함수는 2)해서 전처리기에 의해 치환이되고
인라인함수는 3)에서 컴파일러에 의해 처리된다.
다시말하면 1.매크로의 08번줄은 컴파일에 들어가기전에
r= max(x++,y++);에서 r = x++ > y++ ? x++ : y++;로 바뀌게 된다.
즉, x와 y값의 크기를 비교한 후에 두 변수의 값을 각각 1씩 증가시키고 증가된 x와 y값중에서 큰 값만을 r에 저장한 후에 저장된값만을 1증가 시킨다.
이에 반해 2. 인라인의 경우 일반 함수와 동일하다
call by value를 쓰고 있고, 호출이 이루어진 다음에 변수 x와 y의 값을 1씩 증가시키므로 증가시킨 값이 함수 max()를 호출한 매개변수 값에는 영향을 미치지않았다.
따라서 x와 y의 값은 1씩 증가하여도 r에 저장되는 값에는 변화가 없었던 것이다.-
- 교훈 -
1. 매크로 함수를 사용할 경우에는 보다 신중하자.
매크로문은 선행처리기가 처리하므로 컴파일러가 오류를 찾아내지 못한다. 즉, 잠깐 딴 생각하면서 코딩을 하면 의도했던 바와 다른 결과가 나올수 있다.
2. 인라인화 하고 안하고는 컴파일러 마음이다.
인라인 함수도 컴파일러에 의해 코드의 치환이 일어난다.
일
반함수처럼 원형을 보고 검사하고 호출하는 단계가 없어져 빠르고, 컴파일러가 수행하므로 잘못된 것이 있다면 컴파일타임에 즉시 알수도
있다. but "inline"이라고 지시자를 줘도 인라인화를 시키는 것은 컴파일러맘이다. inline선언을 했다고 다~
inline이 되는 것은 아니다.
3. 실행파일크기를 고려하자
인라인함수이나 매크로함수나 코드의 치환이 일어나기 때문에 loop내에서 호출한다거나 하면 소스의 크기가 무진장 길어진다. 당연히 실행 파일의 덩치가 엄청커진다. 루프에서 쓰지말자
4. 인라인함수는 헤더파일에서...
인라인 함수는 내부 연결성을 가지기 때문에 헤더 파일에 넣어야 어러 소스 파일에서 불러 쓸 수 있다. 따라서 인라인 함수의 정의가 바뀌면 그 인라인 함수와 의존 관계에 있는 사용자 코드는 모두 컴파일을 다시 해야 한다
[Command] Batch Shell Command (0) | 2019.02.23 |
---|---|
[C언어] 주석 TIP (0) | 2019.02.09 |
[C언어] n 에서 m 까지의 합을 재귀로 작정 (0) | 2019.02.09 |
[C++] Vector와 List의 차이점 (0) | 2019.02.08 |
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
//*/ (앞에서 / 하나 빼보시오.)
소스코드
소스코드
소스코드
/*/ (가운데 별 표시를 빼보시오.)
소스코드
소스코드
소스코드
//*/
[Command] Batch Shell Command (0) | 2019.02.23 |
---|---|
[C, C++] 매크로함수 VS 인라인함수 (0) | 2019.02.09 |
[C언어] n 에서 m 까지의 합을 재귀로 작정 (0) | 2019.02.09 |
[C++] Vector와 List의 차이점 (0) | 2019.02.08 |
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
#include <stdio.h>
int sumloop(int,int,int); // 재귀함수의 명시적 선언
int sumloop(int min, int max, int sum) { // 재귀함수 작성
while (min <= max) // 재귀 종료 조건
{
sum += min++;
sumloop(min,max,sum); // 재귀호출
}
return sum; // 마지막 합계 반환
}
void main() { 메인함수
printf("%d\n",sumloop(1,10,0)); // 최소값, 최대값, 합계 파라미터 전달후 바로 결과를 출력하는 구조
}
[C, C++] 매크로함수 VS 인라인함수 (0) | 2019.02.09 |
---|---|
[C언어] 주석 TIP (0) | 2019.02.09 |
[C++] Vector와 List의 차이점 (0) | 2019.02.08 |
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
[C++] 콜백함수( CallBack Function ) (0) | 2019.02.08 |
C++ 환경에서 프로그래밍할 때, 자료구조는
보통 STL를 많이 활용하는데요
vector와 list 활용시 모두 사이즈를 유연하게 할당 할 수 있다는 장점 때문에
item들을 담을 때, 동적인 할당이 요구되는 상황에서 많이 사용하죠.
하지만 이 둘은 분명 차이가 있습니다.
vector 부터 설명드리면,
vector는 내부적으로 배열의 구조를 지니고 있습니다.
그래서 인덱스로 요소에 접근할 경우 상수시간으로 접근 할 수 있죠.
하지만, item들이 추가되거나 삭제를 할 때는
내부적으로 임시 배열을 생성해서 복사한다음
item들을 이동시키게 됩니다. 이런 경우, 비용이 많이 들게 되고 성능이 떨어지죠.
반면, list에서는
item들과의 연결이 포인터로 되어 있어
item의 추가와 삭제가 빠릅니다.
하지만, item들을 검색하는 시간은 o(n)의 비용이 발생하게 됩니다.
vector의 경우는 item들을 저장한 이후 변동이 별로 없다면 효과적이고
list의 경우 item의 추가 삭제가 많을 경우 유용하다고 할 수 있겠습니다.
Java에서도 둘의 자료구조는 동일하게 적용됩니다.
Vector와 LinkedList가 위의 경우와 같다고 생각할 수 있습니다.
단 , ArrayList는 LinkedList와 다르다는 점을 인식하셔야 합니다.
ArrayList는 Vector와 동일한 내부구조를 지니고 있고 다른 점은 멀티쓰레드로
공유자원으로 활용시 Vector는 한 쓰레드가 끝날 때까지 다른 쓰레드의 접근을 막는 동기화의 과정을 철저히 준수합니다.
ArrayList를 활용시 다른 쓰레드의 접근을 허용하지요.
성능을 생각하면 ArrayList이고
동기화의 과정이 준수되어야 하는 상황에서도 사실 ArrayList입니다 - _ -ㅋ;;
왜냐하면, Collection.synchronizedCollection(Collection c)로 동기화 옵션을 설정해줄 수 있기 때문입니다.
Vector는 자바 컬렉션 모델에서 초창기 모델이고 ArrayList는 wrapping된 버젼업 모델이기 때문에
Java에서는 Vector를 잘 사용하지 않는 상황입니다
[C언어] 주석 TIP (0) | 2019.02.09 |
---|---|
[C언어] n 에서 m 까지의 합을 재귀로 작정 (0) | 2019.02.09 |
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
[C++] 콜백함수( CallBack Function ) (0) | 2019.02.08 |
[C++] 정적함수포인터, 멤버함수포인터 (0) | 2019.02.08 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include <iostream> using namespace std; /** * 함수객체 */ void Print(){ cout<<"전역함수!"<<endl; } class Functor{ public: void operator() (){ cout<<"함수객체!"<<endl; } }; // 함수객체란 // 함수처럼 동작하는 객체, 함수처럼 동작하려면 // ()연산자를 정의해야합니다. // 다시말해 ()연산자를 오버로딩한 객체입니다. // 함수객체는 함수자(Functor)라고 불리기도 합니다. int main() { Functor functor; Print(); //전역함수 호출 functor(); //멤버함수호출 functor.operator()와 같다 system("pause"); return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /** * 함수객체를 사용한 콜백함수 구현 */ #include <iostream> #include <algorithm> using namespace std; class Functor1{ //출력 public: void operator()(int n){ cout<<n<<endl; } }; class Functor2{ //제곱 public: void operator()(int n){ cout<<n*n<<endl; } }; int main () { int arr[5] ={ 1, 2, 3, 4, 5 }; for_each(arr, arr+5, Functor1() ); // 임시 함수객체 Functor1을 만들어 함수로 전달 // for_each알고리즘은 함수객체 사용자정의 타입까지도 전달받을수있다. // 여기서보면 전달되는 함수객체 타입이 다른데(1, 2) // 어떻게 그럴수 있을까? 정답은 템플릿이다. cout<<endl; for_each(arr, arr+5, Functor2() ); system("pause"); return 0; } |
장점:
함수객체는 함수처럼 동작하는 개체이므로 다른 멤버변수와 멤버함수를 가질수 있고, 일반함수에서 하지못하는 자원을 받을수 있습니다.
또한, 함수 객체의 서명이 같더라도 객체타입이 다르면 서로 전혀다른 타입으로 인식합니다.속도도 일반 함수보다 함수객체가 빠릅니다.
함수의 주소를 전달하여 콜백하는 경우 이함수 포인터는 인라인될 수 없지만(함수 포인터는 함수가 있어야하므로 인라인 함수의 복사본
함수를 만들어 냅니다) 함수 객체는 인라인될 수 있고, 컴파일러가 쉽게 최적화할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #include <iostream> #include <functional> using namespace std; /** * 함수객체구현및 STL함수객체(less,greater, plus,minus) */ class Less{ public: bool operator()(int n1, int n2){ return n1 < n2 ? true : false; } }; class Greater{ public: bool operator()(int n1, int n2){ return n1 > n2 ? true : false; } }; class Plus{ public: int operator()(int n1, int n2){ return n1+n2; } }; class Minus{ public: int operator()(int n1, int n2){ return n1-n2; } }; typedef less<int> stl_less; typedef greater<int> stl_greater; typedef plus<int> stl_plus; typedef minus<int> stl_minus; int main() { Less l; stl_less l2; Greater g; stl_greater g2; Plus p; stl_plus p2; Minus m; stl_minus m2; cout<< Less()(10,20) <<endl; // 임시객체로 암묵적 함수호출 cout<< l.operator()(20,10)<<endl; // l1객체로 명시적 함수호출 cout<< stl_less()(10, 20) <<endl; // stl less 임시함수객체로 암묵적 함수호출 cout<< l2.operator ()(20, 10)<<endl;// stl less l2 함수객체로 명시적 함수호출 cout<<endl; cout<< Greater()(10, 20) <<endl; cout<< g.operator()(20, 10) <<endl; cout<< stl_greater()(10, 20) <<endl; cout<< g2.operator ()(20, 10)<<endl; cout<<endl; cout<< Plus()(10, 20) <<endl; cout<< p.operator()(20,10) <<endl; cout<< stl_plus()(10, 20)<<endl; cout<< p2.operator ()(20, 10) <<endl; cout<<endl; cout<< Minus()(10, 20) <<endl; cout<< m.operator()(20, 10) <<endl; cout<< stl_minus()(10, 20) <<endl; cout<< m2.operator ()(20, 10)<<endl; system("pause"); return 0; } |
[C언어] n 에서 m 까지의 합을 재귀로 작정 (0) | 2019.02.09 |
---|---|
[C++] Vector와 List의 차이점 (0) | 2019.02.08 |
[C++] 콜백함수( CallBack Function ) (0) | 2019.02.08 |
[C++] 정적함수포인터, 멤버함수포인터 (0) | 2019.02.08 |
[C++] 템플릿 (함수템플릿, 클래스템플릿) (0) | 2019.02.08 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include <iostream> using namespace std; /** * 클라이언트 코드와 서버코드 * 서비스를 제공하는 코드측을 서버코드 * 그기능을 제공받는 코드측을 클라이언트코드 */ //서버// void PrintCall(){ cout<<"HelloWorld"<<endl; } //클라이언트// int main(){ PrintCall(); /** * 이처럼 클라이언트가 서버를 * 호출하게되면 Call * 반대로 서버가 클라이언트를 호출하게되면 * 콜백(CallBack) */ // 윈도우의 모든 프로시저는 시스템이 호출하는 Callback함수 system("Pause"); return 0; } |
서버에서 클라이언트 코드 호출 ( 콜백함수 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <iostream> using namespace std; //서버 코드영역// void PrintCall(){ cout<<"HelloWorld"<<endl; Client(); } //클라이언트 코드영역// void Client(){ cout<<"난 클라이언트"<<endl; } int main(){ PrintCall(); // 서버에서 클라이언트측 코드인 Client() 함수를 호출하면 // 이때 Client()함수를 '콜백함수'라 합니다. // 서버는 여러클라이언트에의해 호출되며 클라이언트의 존재를 알수없는데 // 위의 예제처럼 서버에서 클라이언트 코드를 알고 호출하는것을 불가능 // 합니다. 그래서 서버에게 알려줄필요가 있는데 // 그방법으론 함수포인터매개변수를 이용한 콜백함수의 주소를전달하는방법 // 객체,대리자,전략패터등을 사용 // 말그대로 서버는 구체적인 작업이 없이 클라이언트 함수의 의해서 작업 // 내용이 결정납니다. // 윈도우의 모든 프로시저는 시스템이 호출하는 Callback함수 system("Pause"); return 0; } |
// 함수포인터매개변수를 이용한 콜백함수의 주소를전달하는방법
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <iostream> #include <algorithm> using namespace std; //서버 코드영역// void For_each(int *begin, int *end, void (*pf)(int) ){ while(begin != end){ pf(*begin++); // 클라이언트 함수 호출 콜백 } } //클라이언트 코드영역// void Print1(int n){ cout<< n << endl; } void Print2(int n){ cout<< n*n <<endl; } int main(){ int arr[5] = {10, 20, 30, 40, 50}; For_each(arr, arr+5, Print1); cout<<endl; for_each(arr, arr+5, Print2); /** * 서버코드는 단지 클라이언트함수를 처음부터끝까지 * 호출해주기만 한다. 추상화 * 출력정책은 클라이언트에서만 알고있고, 수정한다. */ system("Pause"); return 0; } |
[C++] Vector와 List의 차이점 (0) | 2019.02.08 |
---|---|
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
[C++] 정적함수포인터, 멤버함수포인터 (0) | 2019.02.08 |
[C++] 템플릿 (함수템플릿, 클래스템플릿) (0) | 2019.02.08 |
[C++] 연산자 오버로딩 (0) | 2019.02.08 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #include <iostream> /** * 정적함수포인터, 멤버함수포인터 */ using namespace std; class Point{ int x; int y; public: Point( int _x = 200, int _y = 300 ) : x(_x), y(_y) {} void Print(){ cout<<x<<","<<y<<endl; } void Print(int num){ cout<<num<<":"<<x<<","<<y<<endl; } void Print(int x, int y){ cout<<x<<","<<y<<endl;} }; void Print( int x, int y ){ cout<<x<<","<<y<<endl; } int main(){ //[전역함수, namespace전역함수, static멤버함수] void (*pf)(int, int) = Print; // 정적함수포인터 pf(1000,2000); /** * 클래스 멤버 함수포인터 선언이 다른것은 * 함수호출규약이 틀리기때문인데, 정적함수포인터는 cdecl이고, * 멤버함수는 thiscall규약을 따릅니다. * */ /** * pt객체로 멤버함수포인터를 이용한 호출문 */ Point pt(10,20); void (Point::*pf2)(int) = &Point::Print; (pt.*pf2)(100); void (Point::*pf3)(int, int ) = &Point::Print; (pt.*pf3)(30,40); /** * pt주소값으로 멤버함수포인터를 이용한 호출문 */ Point *pAddress = &pt; void (Point::*pf4)(int) = &Point::Print; (pAddress->*pf4)(40); system("pause"); return 0; } |
[C++] 함수객체 ( Functor ) (0) | 2019.02.08 |
---|---|
[C++] 콜백함수( CallBack Function ) (0) | 2019.02.08 |
[C++] 템플릿 (함수템플릿, 클래스템플릿) (0) | 2019.02.08 |
[C++] 연산자 오버로딩 (0) | 2019.02.08 |
[C++] 가상소멸자 (0) | 2019.02.08 |