프로그래밍/C++2012. 4. 25. 11:55

1. cout, endl의 원리

 

cout은 원래 객체이며, endl의 경우 함수이다.  아래는 cout과 endl를 구현해 본 소스코드이다.

 

추가로 tab이나 two_endl의 사용자정의 함수도 추가했다. 

 

그럼 이게 기존거랑 충돌이 나느냐? 아래를 보자.

위와 같이 우리가 만든 함수들도 기존 std 네임스페이스와 같이 쓸 수 있다.

 

cout은 c와 달리 출력 형태가 무엇인지 정해주지 않아도 된다. 그렇다면 사용자 정의 객체 일 경우 어떻게 해야 할까?

아래는 사용자 정의 객체인 Point를 만든 코드이다.

 

cout << p;  이 부분은 결국 cout.operator<<(Point)가 있으면 된다.

 

만약 namespace를 쓴다면, 어떨까? cout은 이미 라이브러리에서 정의된 것인데, Graphic::을 붙일 수 없지 않은가?

그래서 2일차에서 나왔던 키네그 룩업이라는 기법을 써서, 어차피 Point라는 객체가 존재하는 namespace를 찾아서 쓸 수 있게 하는 것이다.

이런 문법들이 왜 이렇게 설계되었는지 더 자세히 알고 싶으면, Annoted Reference Manual : C++을 참조하라.

 

 

2. 변환 연산자

 

 

 

변환 연산자를 생성하면 된다.  변환 생성자도 추가됐다.

 

 

 

 

 

 

3. new 연산자 이야기

 

 

new를 오버로딩하는 것도 가능하다.

 

memory leak 검사하기

 

 

placement new 개념

// placement new 개념
// 1. 기존의 메모리에 대해서 생성자를 호출할 때 사용하는 기술
// 2. new(기존메모리 주소) 타입;
// 3. C로  할당한 메모리(공유메모리등)을 객체처럼 사용하려고...
// 4. 또는 Template을 활용한 고성능 라이브러리 만들 때 주로 사용
//    안드로이드의 typehelpers.h 가 이 기술 사

 

분명히 new에서는 메모리 할당을 하지 않았음에도 불고하고, 객체를 리턴함으로써 생성자/소멸자를 호출한다.(확인)

 

 

 

 

안드로이드에서는 프로세스간 Binder를 써서 통신하는데, 이때 쓰는게 mmap이다. 이와 비슷하게

 

 

이제 new와 예외처리에 대해서 알아보자.

 

멀쩡해 보이나?  1998년 이후, new가 실패 했을 경우, 더 이상 0을 리턴하지 않는다.

 

대신 다음과 같이 try... catch블록을 써서 체크해야 한다.

 

 

 

만약 아래와 같이 메모리가 부족하면, p2의 생성자는 소멸이 되는가??

 

안된다. 완전하게 끝난 생성자만 소멸이 가능하다.

 

그래서 두가지 해결책이 있다.

첫째로 스마트 포인터를 사용한다.

 

두번째로 생성자에서 자원을 할당하지 말고 자원할당 전용함수를 만들어 사용한다.

 

전체적인 소스는 다음과 같다.

 

 

4. 함수객체

 

함수객체에 대해서 알아보자.

 

예제처럼, 객체를 함수처럼 연산자 오버로딩을 통해서 사용할 수 있다.

 

전에 함수포인터는 inline 치환이 불가능했었는데, 함수객체를 사용하면, 가능하게 된다.(예제만 설명하느라 컴파일은 안된다)

함수객체의 장점은 즉, inline함수를 쓸 수 있으니, 빠르다는 점이 있겠다

 

sort를 통해서 함수객체에 대해서 더 알아보자.

 

좀 더 다듬어 보자.

 

 

 

쉬어가는 코너

 

 

5. STL

아래의 코드를 참조하자.

 

6. 상속

생성자는 부모 먼저 불리우고, 자식의 생성자가 불리며 소멸자는 반대의 순서이다.

Dog()에서 비록 우리가 아무런 부모생성자 호출 코드를 안 넣었어도 컴파일러가 Dog() : Animal() { ...} 이런 식으로 추가해 준다.  즉 부모 생성자가 먼저 만들어지더다라도, 자식 생성자가 먼저 호출은 된다.

 

protected에 대한 문제

protected 생성자는 자신은 만들 수 없지만, 자식은 만들 수 있게 하는 기술.

 

어떤 관계로 상속 받았냐에 따라서 자식이 물려받은 변수에 영향을 미친다.

 

근데 왜 private을 쓸까? (정말 몰라서 묻는건 아니고, 다음 예제를 보자는 말이다)

 

Vector클래스의 상속권한을 private으로 바꾸자.

 

 

7. Upcasting

자식 클래스는 public으로 상속 받았을 경우, 부모가 요구되는 인자에 자식 클래스로서 갈 수 있다.

좀 더 자세한 Upcating에 대한 소스를 보자.

 

 

 

8. 함수 오버라이딩

 

부모의 함수가 적당하지 않을 때, 같은 이름의 함수로 오버라이드를 할 수 있다.

예를 들어,

Anima* p = &Dog;

라고 있을 때,

p->Cry()

라고 하면,

A:Cry(),

B:Cry()

중 어느 함수를 불러야 할지 결정하게 되는데 이를 바인딩이라고 한다.

 

바인딩(binding)은 다음의 두 종류가 있다.

 static binding(early binding) 

 컴파일러가 컴파일시간에 결정. 원리는 포인터 타입으로 호출

 c++, c#

 dynamic binding(late binding)  컴파일러가 컴파일시 메모리 조사하는 코드를 생성.  실행시 메모리에 어떤 객체가 있는지 조사해서 호출
 java, objective-c, c++(virtual), c#(virtual)

 

관련된 코드는 아래를 참조하자.

 

 

마지막으로 OOP 개념을 살린 예제 코드 한번 보자.(두번 보자)

 

 

   모든 자식에 공통의 전체 알고리즘은 부모가 제공한다.
   하지만 변경되어야 하는 세부 알고리즘은 protected 가상함수로 제공한다.
   전체 알고리즘함수에서 세부 알고리즘 함수를 호출해서 세부알고리즘은 자식이 변경 할 수 있게 하자!

Binder의 Iinterface내에 이 디자인 패턴을 사용했다.

'프로그래밍 > C++' 카테고리의 다른 글

Android Framework 분석을 위한 C++ 4일차  (0) 2012.04.26
[C++] Smart Pointer  (0) 2012.04.25
swap 함수  (0) 2012.04.25
Android Framework 분석을 위한 C++ 2일차  (0) 2012.04.24
Android Framework 분석을 위한 C++ 1일차  (0) 2012.04.23
Posted by code cat
프로그래밍/C++2012. 4. 25. 00:39

갑자기 생각나서...

Posted by code cat
프로그래밍/C++2012. 4. 24. 10:52

이 글의 모든 소스는 Android Framework 분석을 위한 C++ 강좌에 사용된 코드이며 저에겐 코드에 대해 아무런 권리도 없음을 밝힙니다.

 

1. 초기화 리스트(Colon Initialize)

 

클래스 멤버로로 상수나 참조 멤버가 있는 경우, 반드시 초기화리스트로 초기화해야 한다.

 

만약 디폴트 생성자가 없는 객체를 멤버로 가질 때 초기화 리스트로 초기화 해야 한다.

 

주의할 점은, 초기화는 클래스의 멤버가 선언된 순서대로 초기화 된다.

 

참고로 생성자를 클래스 외부에 구현했을 때 초기화 리스트는 다음 줄에 표기하자.

 

 

2. 상수 함수

상수 함수가 필요한 이유

 

우선 다음과 같은 코드를 보자.

 

근데 뭐 나는 const가 들어 갈 함수 안에 값을 안 바꿀거니, const 따위 필요 없다! 라고 생각하고 한번 제외하고 코드를 짜보자. 그러면 , print는 안에 아무것도 변하지 않으니 실행될 거 같지만?.. 안된다!

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

 

그러면 뭐 난 상수랑 안 쓰겠다? 하면 될까? 다음 코드를 보자.

 

결론은 라이브러리 제작이나 완전한 클래스를 제공할려면 const를 만들어야 한다.

간단한 룰은 값을 변하게 하는 함수라면 const가 필요 없으나, 그 외에는 const를 붙여야 한다.

 

 

3. 복사 생성자

 

 

다음의 코드를 실행하면 결과가 어떻게 나올까?

 

결과는 다음과 같다.

 start
 생성자2
 AAA
 복사생성자 - p
 foo
 소멸자 - p
 BBB
 소멸자

 

여기서 다시 성능향상을 위해서 다음과 같이 수정하자.

 

 

다음 코드의 결과를 예측해 보자.

 

결과는 다음과 같다.

 start
 생성자1 - p1
 AAA
 생성자2 - p2
 foo
 복사생성자 - 임시객체
 소멸자 - p2
 소멸자 - 임시객체
 BBB
 소멸자

 

다시 성능 향상을 위해 임시객체에 대한 작업을 하려고 하지만, 예전과 달리 이번에는 전역객체가 아닌 지역객체를 리턴함으로, 다음과 같이 하면 안된다. (지역변수등을 리턴할 때, 참조를 쓰면 안된다.)

 

대신 RVO를 써서, 다음과 같이 바꾸면 된다.

 

한가지 주의할 점은, 만약에 우리가 복사생성자를 다음과 같이 만들었다고 치자(성능은 잠시 접어두고)

복사 생성자가 인자로 디폴트를 넘기는 이게 또 복사 생성자를 부르고 하는 무한 반복 코드가 되서 컴파일 에러가 난다.

 

 

복사 생성자는 또 디폴트 복사 생성자에 대한 문제점이 있는 해결책은 다음의 4가지이다.

    (A) 깊은 복사    - 가장 널리 알려진 기술. 하지만 별로 좋지 않다.   

    (B) 참조 계수    - 가장 많이 사용하고, 가장 좋은 기술
    (C) 소유권 이전 - 많이 사용하고 있진 않지만 swap등을 만들 때 좋다.
                             STL의 auto_ptr<>이 이 기술 사용
    (D) 복사 금지

 

우선 기본적으로 얕은 복사 때문에 생기는 문제의 코드다.

 

깊은 복사 (성능의 문제가 있다)

 

참조계수(Referecen Counting)

 

소유권 이전 (살짝 헷갈리는 부분)

 

복사 금지

 

 

 

4. 싱글톤

오직 한개의 객체만을 만드는 디자인 패턴

 

우선 기본적인 코드를 보자.

 

이번엔 객체를 힙으로 만들자.

 

 

만약 우리가 Cursor말고도 KeyBoard라는 클래스를 똑같이 만들고 싶다면, 다음과 같이 코드 자동 생성을 작성해 보자.

 

 

 

아쉽게도 안드로이드에서는 템플릿을 응용한 기술 + 상속 기술을 사용한다. (템플릿이 조금 어렵게 구현된다) 이런한 기술을 mix in template이라고 한다.

 

 

 

5. This

 

기본적인 this의 사용법이다.  여기서 cout또한 this를 이용한 것을 볼 수 있다.

 

p1, p2처럼 2개의 Point를 생성하면, 각 멤버 data는 객체마다 존재하지만, 코드는 공유를 한다. 그럼 어떻게 멤버 함수가 불리울 때, 어느 객체인지 알 수 있을까?

위와 같이 컴파일 시에는 객체에 대한 인자를 넘길 수 있는 형태로 변환된다.  추가적으로 static의 경우 this가 필요치 않고, 사용할 수 없다.

 

 

6. 멤버 함수 포인터

 

 

 

 

 

 

 

7. 연산자 재정의

 

 

위의 코드에서 보면, 멤버 함수와 일반 함수의 용도에 따라 약간 다른 컴파일 결과가 나오는데,

일반 함수 vs 멤버 함수는 쉽게 생각해서, 연산의 결과로 멤버가 바뀔 거면(private이면) 일반함수에 접근이 불가능하기 때문에 멤버 함수로 하는게 좋고, 아닐 경우, 일반 함수로 하면 좋겠다. 

 

증감연산도 보자.

우리가 만든 Int32도 당연히 ++가 잘 동작해야 한다. 하지만 오동작을 하는 것을 볼 수 있다( 5가 나오는 대신 4)

 

이를 수정하려면, 참조리턴을 해야 한다.

 

마찬가지로 후위형 또한 다음과 같이 할 경우가 문제 생기는데,

 

이를 수정하려면, 다음과 같이 한다.

한번 보면, (n2.operator++(int))는 Int32 n2가 상수가 아니기에 const Int32 operator++를 부르는데 문제가 없으나, 이를 통해 리턴되는 녀석은 상수(const)이다. 그럼 다시 (n2.operator++(int)).operator++(int)를 부르라고 하면, %상수 객체는 상수 함수만을 부를 수 있다%, 상수라서 부를 수 없다.

 

그리고 성능 향샹을 위해 전위형은 inline으로, 후의형은 다시 전위형을 호출하게 하자.

 

이걸로 보면 전위형이 후위형보다 성능이 좋다는 걸 알 수 있다.

for(int i = 0; i < 10; i++) 보다 for(int i = 0; i < 10; ++i)가 좋다는 말이다. 그러나 역시 똑똑한 우리의 컴파일러는 컴파일 시 이를 최적화 해 주므로 가독성을 위해 i++을 써도 된다.

 

 

8 스마트 포인터

 

스마트 포인터를 설명하기 위한 기본 코드를 보자.

 

변형을 조금 가해서 코드가 조금 어려워 진다.

sptr p를 보면.. sptr은 포인터가 아니고, sptr 타입인데, p->Go()를 보면 포인터같고 Car타입 같다.. >_<

sptr 안에는 Car* 포인터가 존재하고 sptr p = new Car 는 결구 sptr p(new Car)와 같다.

p->Go()의 경우 위에 정의된  operator->()에 따른다.

 

이것이 스마트 포인터라고 불리우는데, 이는 포인터가 아닌 객체(다른 객체의 포인터 역활을 한다.)이며, 스마트 포인터의 장점은 생성/복사/대입/소멸의 모든 과정을 사용자가 정의 할 수 있다는 것이다.

 

아래는 template을 써서 위의 sptr을 일반화한 코드이다.

 

스마트 포인터와 참조계수에 대해서 알아보자.

 

 

그러나 스마트포인터는 레퍼런스카운터에 대한 포인터 때문에 오버헤드가 있다. 그럼 레퍼런스를 객체에 두어보자.

 

 

마지막으로 안드로이드에서 쓰는 방식을 따라서 써 본 코드이다.

안드로이드는 객체가 만들어지면 레퍼런스 카운터가 1이 되고, 스마트 포인터로 가리키면 2가 된다.(보통 0에서 시작해서 스마트 포인터가 가리키면 1이된다).

 

 

9. 반복자

 

 

 

 

 

 

 

 

'프로그래밍 > C++' 카테고리의 다른 글

Android Framework 분석을 위한 C++ 4일차  (0) 2012.04.26
[C++] Smart Pointer  (0) 2012.04.25
Android Framework 분석을 위한 C++ 3일차  (0) 2012.04.25
swap 함수  (0) 2012.04.25
Android Framework 분석을 위한 C++ 1일차  (0) 2012.04.23
Posted by code cat
프로그래밍/C++2012. 4. 23. 17:43

아래 내용은 Android Framework 분석을 위한 C++ 강의를 정리한 내용으로 사용된 모든 소스는 강의에서 나옴을 밝힙니다.

 

개발환경:

Visual Studio 2010 Express

 

참고하기에 좋은 문서/책:

문법: Effectiv c++

template c++ template programming

디자인 패턴 : GoF's 디자인 패턴

 

visual c++ 개발환경에서 기본적인 빌드/실행: 

build                  : F7

build + execute   : ctrl + F5

 

1. 헬로 월드

 

Visual Studio 2010 Express에서 리소스 부분의 .cpp 파일을 클릭해서 빌드에서 제외 하면 컴파일을 안 시키고 다른 소스를 계속 추가해서 실험해 볼 수 있음.

 

 

2. 함수 오버로딩

console에서 컴파일을 할 때, 리눅스의 경우 gcc를 사용하지만, 윈도우는 cl.exe를 사용하며 다음과 같이 컴파일 한다.

cl filename.cpp

cl filename.cpp /FAs  //assembly 소스를 만들어 달라고 요청

 

이제 오버로딩을 보자.(asm파일을 쉽게 보기 위해, iostream은 제외했다)

 

asm파일을 열어보면, 오버로딩 된 함수에 대한 이름이 각기 다른 것을 알 수 있다. (함수오버로딩의 결과물)

보다시피 int 인자를 가진 함수는 ?square@@YYHH@Z 이고, double 인자를 가진 함수는 ?square@@YANN@Z라고 보인다.

 

그럼 다음과 같이 하면 어떨까?

 

컴파일 시에는 각기 컴파일을 한 뒤 링크 과정을 거침으로, c와 c++의 혼합 컴파일 시, c에 정의된 함수는 오버로딩을 지원하지 않는 관계로 name mangling(컴파일 시 같은 오버로딩함수들의 이름을 다른 심볼 이름으로 교체)현상이 없고, 이로 인해 cpp파일의 컴파일 후, 링킹 과정에서 위에서 본 바와 같이 ?sqaure형식의 심볼이름을 찾으려다 못 찾아서 에러가 난다.

 

 

이를 해결하기 위해선, 함수 앞에 extern "c"를 붙여 주면 된다.

그러나, 만약 오버로딩함수2.cpp를 c로 변형한다면 역시나 에러가 난다. 이는 extern "C"는 cpp에서만 지원하기 때문이다.

 

 

cpp에서는 ifdef __cplusplus내의 모든 함수에 extern "C"가 붙고 c의 경우 제거된다.

 

결론은, header파일에 __cplusplus 라는 매크로를 쓰고, c나 cpp에서 부르면 된다. 

 

우리가 자주 쓰는 stdio.h에서도 이와 같은 매크로가 있어서 우리가 c 이던  c++ 이던, 상관하지 않고 쓸 수 있다.

 

추가적으로 overloading 된 함수를 찾는 순서는 다음과 같다.

1. Exactly matching.                        인자와 정확히 들어 맞는 type이 있는 함수를 먼저 찾는다.

2. Promotion.                                  인자가 변환될 때 data의 손실이 없는 타입을 가진 함수가 있는지 찾는다.

3. Standard Conversion                   암시적인 변환이 가능한 타입을 가진 함수를 찾는다.

4. user defined conversion operator  사용자가 만든 변환 연산자가 있으면 변환 후, 함수를 호출한다.

5. '...'                                           가변인자를 갖는 함수는 type에 무관하므로 이를 호출한다.

 

3. 인라인함수

 

위의 코드를 console에서 컴파일 할 경우, 그냥 하면 inline이 컴파일러에 의해 무시된다.  제대로 할려면 다음과 같이 해보자.

 

cl.exe fileName.cpp /Ob1 /FAs  // 인라인을 쓰겠다고 컴파일러에게 알려준다. 그럼 이렇게 생성된 asm파일을 보면,

 

 

우리가 일반적으로 inline을 쓸 경우, 속도가 빨라지나 obj 파일이 커질거라고 생각하나, 간단한 inline함수의 경우 오히려 크기가 작아진다.(asm파일을 참조하라)

 

console이 아닌 Visual C++ IDE에서 컴파일 시, debug옵션이면 inline을 거부하나, release일 경우 inline옵션으로 컴파일 되어 진다.

 

 

inline함수를 쓸 때 주의해야 할 점이 있다. 다음을 보자.

보통 헤더파일에 선언을 하고, 소스파일에서 구현을 하기 때문에, 인라인함수도 그런 식으로 한다면? 빌드 에러난다.  왜냐면, 인라인 함수에 대한 치환은 컴파일러가 담당하므로, 컴파일시, 인라인 함수에 대한 정의가 완전하게 나와야 한다.  즉 인라인 함수에 대한 정의가 치환 시점 전에 있거나, include되는 헤더파일 안에 있어야 한다.  다시 말하면, inline함수는 internel linkage를 갖는다.

 

참고로,

 

internal linkage : 임의의 심볼이 선언된 컴파일 단위(파일)에서만 사용가능.  internal linkage는 주로 헤더에 만든다.

예) static 전역변수, 인라인 함수, 매크로 상수/함수, 함수/클래스 템플릿, 구조체

 

external linkage : 임의의 심볼의 프로젝트내의 모든 컴파일 단위에서 사용가능

예) 전역변수, 일반함수

 

예제)

template<typename T> T square(T a){return a * a;}    internal linkage

int a;                                                                     다른 파일에서 extern int a;라고 선언 후 접근 가능

static int b;                                                             다른 파일에서 접근 불가.

const int c = 0;                                                       .c에서는 external

                                                                            .cpp에서는 internal

#define    MAX 10                                                   internal linkage

struct People {};

 

 

4. 함수 템플릿

 

c의 경우 필요시 코드 생성 기술을 다음과 같이 활용한다.

 

 

C++에서는 함수 tempalte을 써서 컴파일러가 처리할 수 있다.

 

반면에 template은 잘못 사용하면, 다음과 같은 결과가 생긴다.

 

 

한편 다음과 같은 경우는 어떨까?

 

T가 결정되어서 함수 템플릿이 진짜 함수가 되는 과정: "인스턴스화"라고 하고 "명시적 인스턴스화" 와 "암시적 인스턴스화"가 있다.

이렇게 위와 같이 <int>로 프로그래머가 정한 것을 명시적 인스턴스화 라고 한다.

암시적 인스턴스는 컴파일시 컴파일러에 의해 결정되는 것을 말한다.

 

 

5. 캐스팅

한마디로 C에서의 캐스팅은 위험하다.  물불 안 가리고 캐스팅을 하기 때문이다.  자세한 내용은 밑의 소스 코드를 참조하자.

 

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

출처: http://ikpil.com/262

static_cast 는 C 스타일 캐스트와 똑같은 의미와 형변환 능력을 가지고 있는, 기본적인 캐스트 연산자입니다. C 스타일의 그것과 구실이 똑같다 보니 받는 제약도 똑같습니다. 예를 들어,struct 를 int 타입으로 바꾼다든지 double을 포인터 타입으로 바꾸는 일은 이것으로 할 수 없습니다. 게다가, static_cast 는 표현식이 원래 가지고 있는 상수성(constness)을 떼어버리지도 못합니다. 이런 일을 하는 캐스트 연산자인 const_cast 가 따로 있는 것을 보면 짐작할 수있지요.
나머지 세 가지의 C++ 캐스트 연산자는 좀 더 구체적인 목적을 위해 만들어졌습니다. const_cast는 표현식의 상수성이나 휘발성(volatileness)을 없애는 데에 사용합니다. 이 연산자가 쓰여진 소스를 만나면, 아, 이 개발자는 const 나 volatile로 선언한 변수라든지 이런 타입의 값을 내는 표현식에서 이런 특성만 바꾸고 싶어하는구나 라고 생각하면 되겠습니다. 이러한 프로그래머의 의도는 컴파일러에 의해서 더욱 확실해집니다. 즉, 상수성이나 휘발성을 제거하는 것 이외의용도로 const_cast 를 쓰면 통하지 않습니다.

구체적인 용도를 가진 C++ 캐스트 연산자 두 번째는 dynamic_cast 입니다. 이 연산자는 상속
계층 관계를 가로지르거나 하향시킨 클래스 타입으로 안전하게 캐스팅할 때 사용합니다. 말하자
면, dynamic_cast 는 기본 클래스의 객체에 대한 포인터나 참조자의 타입을 파생(derived) 클래
스, 혹은 형제(sibling) 클래스의 타입으로 변환해 준다는 것입니다3). 캐스팅의 실패는 널 포인터
(포인터를 캐스팅할 때)나 예외(참조자를 캐스팅할 때)를 보고 판별할 수 있습니다

네 가지 C++ 캐스트 연산자의 마지막은 reinterpret_cast 입니다. 이 연산자가 적용된 후의변환 결과는 거의 항상 컴파일러에 따라 다르게 정의되어 있습니다. 따라서, 이 연산자가 쓰인소스는 직접 이식이 불가능합니다.
reinterpret_cast 의 가장 흔한 용도는 함수 포인터 타입을 서로 바꾸는 것입니다. 예를 들어, 어떤 특정한 타입의 함수 포인터를 배열로 만들어 놓았다고 가정합시다.
typedef void (*FuncPt r) ( ) ; // FuncPtr 은 인자를 받지 않고
/ / void를 반환하는 함수에 대한
/ / 포인터입니다.

FuncPtr funcPtrArray[10]; // funcPtrArray는 10개의 FuncPtr로 만들어진 배열입니다.
이때 다음의 함수에 대한 포인터를 funcPtrArray에 넣어야 할 피치 못할 사정이 생겼습니다.
int doSomething();
간단할 것 같지만 캐스팅을 하지 않으면 절대로 안 됩니다. 왜냐하면 doSomething은 funcPtrArray에 넣기에는 타입이 맞지 않기 때문입니다. 이 배열에 들어가는 함수는 void를 반환하지만, doSomething은 i nt 를 반환하지 않습니까?
funcPtrArray[ 0 ] = &doSomething ; / / 에러입니다! 타입불일치이군요.
reinterpret_cast 를 쓰면 컴파일러에게 이 일을 강제로 시킬 수 있습니다.
funcPtrArray[ 0 ] = / / 이것은 컴파일됩니다.
reinterpret_cast <FuncPtr> (&doSomething) ;

 

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

 

6. 레퍼런스

 

변수 선언을 했다고 치자.

그럼 메모리가 할당되고, 이를 만약 포인터 변수를 써서 assign했다 치자. 그럼 역시 변수를 가리키는 주소를 가지는 포인터가 메모리에 생긴다.  이와는 달리 레퍼런스의 경우, 별다른 메모리를 차지않고 기존 메모리에 대한 별명이라고 보면 된다.

 

 

 

다음을 보자.

 

답은 다음과 같다.

foo()를 호출 했을 때, p를 리턴하는데, 이는 임시객체를 리턴한다.  그러므로, 위에 정의된 구조체에 영향을 미치지 않는다.

당연히 p.x를 출력하면, 1이 출력된다. 

 

한편 임시객체를 리턴할 경우, 생성자/소멸자 등이 불리우고 메모리가 잡히기 때문에 성능에 큰 영향을 미친다. 

그럼 어떻게 해야 할까?  다음과 같이 레퍼런스를 사용하면 된다.

 

 

정리하자면,

임의의 함수가 값을 리턴하면,
     1. built in type인 경우, (ex: int foo() )       : 상수로 리턴된다.
     2. user defined type인 경우, (ex: Point foo() ) : 임시객체가 리턴된다.

 

어떤 함수의 리턴값이 참조라면
     1. built in type  (int& foo) : 함수 호출을 lvalue에 놓게다는 의미
         foo() = 10;
     2. user type ( Point& foo() ) : 임시객체를 제거하겠다는 의미!

 

 

참조 변수와 함수 인자

여기서 정리하고 가는 단계로 다음의 코드를 보자.

 

주의할 점은 inc3(z)로 z를 패스하는데, &z를 패스하지 않도록 주의한다.

이렇게 보면 레퍼런스로 받는게 코드 복잡성에서도 나아보이고, 메모리 구조면에서도 좋아보이나, 코드 가독성 측면에서 포인터가 더 좋다.( inc3(z)를 본다면, z가 변할지 안 변할지 알아보기 힘들다. 그러나 inc2(&y)를 보면 딱 봐도 y가 변할 거라는게 보이지 않는가?)

 

그러나 레퍼런스 인자를 쓸 일이 있는데 다음을 보자.

 

 

한가지 재밌는 것은, 다음의 경우다.

위에서 막 레퍼런스를 얘기했으니 2번 같겠지만, 1번이다.  int같은 경우 overhead가 크게 일어날 경우도 없고, const T&를 쓸 경우, 컴파일러가 최적화를 할 수 가 없다.

 

혼돈스러우니, 정리하자면,

함수가 값을 변경하지 않는다면 const T&를 사용하자.
  (A) built in type의 경우 : call by value 가 좋다.

         foo( int a )
  (B) user type 의 경우    : const T& 를 사용하자.
         foo( const Data& a )

 

 

 

7. Namespace

 

다음과 같이 코드를 짜다보면 같은 이름을 쓰고 싶은데 중복될까봐 이런 식으로 쓰게 되는 경우가 있는데,

이걸 매번 확일 할 수도 없고, 그래서 사용할 수 있는게 namespace이다.

 

이렇게 같은 함수 이름을 중복해서 써도, namespace만 정의 잘하면 문제 없이 쓸 수 있다.

 

참고로, #include <iostream.h> 에는 cout, endl이 전역공간에 있다. 그러나 <iostream>의 경우,

namespace std

{

   // cout, endl이 여기 있음.

}

와 같이 되어 있다.

 

한가지 더 알면 좋은 거 추가...

 

 

8. OOP 개념

 

다음의 코드를 보자.

 

 

복소수를 리턴하기 위해 복잡하게 리턴을 하는 것보다, 구조체를 만들어 보자.

 

 

다음은 OOP개념을 익히기 위해 기본적인 C의 방법부터 코드를 수정하는 과정이다.

 

 

 

9. 생성자 정리

 

 

'프로그래밍 > C++' 카테고리의 다른 글

Android Framework 분석을 위한 C++ 4일차  (0) 2012.04.26
[C++] Smart Pointer  (0) 2012.04.25
Android Framework 분석을 위한 C++ 3일차  (0) 2012.04.25
swap 함수  (0) 2012.04.25
Android Framework 분석을 위한 C++ 2일차  (0) 2012.04.24
Posted by code cat
리눅스2012. 4. 17. 10:46

우선 이게 되는지는 나도 정확히 모르겠으나, 될 거 같다. 안될 이유가 있는가??


그냥 대놓고 startx하면 Xauthority 가 없다 이런 에러가 날 것이다.

우선 기본적으로 ssh -X 계정이름@호스트이름으로 접속해 보자.


접속되고 나면 Xwrapper.config를 바꿔야 하는데, /etc/X11/Xwrapper.config는 다음과 같이 3가지 값을 가질 수 있다.
    root
    anybody
    console
allowed_users=anybody로 값을 바꾸자.


그 후 만약 startx 하고 돌렸는데,


    "Server is already active for display 0"


하고 나오면 당연히 서버가 display 0을 쓰고 있을 것이다.

그래서 startx -- :1로 display 1으로 실행시킨다. 나중에 돌리다 보면 필요하겠지만, display 1로 실행시킨 녀석을 죽일라면


    rm -rf /tmp/.X1-lock


을 사용하자.

그런데 이제는 "Failed to load module "fglrx" 가 나온다.

(==) Log file: "/var/log/Xorg.1.log", Time: Mon Apr 16 20:22:59 2012
(==) Using system config directory "/usr/share/X11/xorg.conf.d"
(EE) Failed to load module "fglrx" (module does not exist, 0)

그럼 다음과 같이 해보자.


    sudo dpkg-reconfigure -phigh xserver-xorg

그리고 다시 start -- :1을 실행. 여기서 display 1이 안될 수도 있으니, 위에 말한 rm -rf /tmp/.X1-lock을 사용하고 다시 해보자.

이번엔 이렇게 나온다.
_XSERVTransSocketINETCreateListener: ...SocketCreateListener() failed
_XSERVTransMakeAllCOTSServerListeners: server already running


Fatal server error:
Cannot establish any listening sockets - Make sure an X server isn't already running

이 경우, 위에서 lockfile을 날려서거나, lock file을 만들지 않는 어떤 넘이 벌써 포트로 listening 중이기 때문이다.
이럴 땐 이렇게 해보자.


netstat -ln


여기서 무슨 값을 봐야 하나면, x서버는 6000대의 포트 + display 값로 listening을 한다. 그러니 6001을 보자.


      netstat -ln | grep "6001"

여기서 막혔는데 좀 더 봐야겠다.

'리눅스' 카테고리의 다른 글

[EXT4] barrier=1 혹은 0에 대한 옵션 설명  (0) 2013.11.24
[Mint Linux] gnome shell emulation  (0) 2012.09.08
ext4분석  (0) 2012.04.10
EXT4 파일 시스템 굽기(2)  (0) 2012.03.18
GOT (Global Offset Table)  (0) 2012.03.02
Posted by code cat
리눅스/커널2012. 4. 16. 09:07

아키텍쳐 별로 tag를 만들어서 분석 시 좀 더 편하게 분석 하는 방법이 있는데, (뭐 물론 아키텍쳐별로 파일 다 지우고 하겠다면 안 말린다)


1. tag 생서시에는

make tags ARCH=<architecture name>


2. cscope 생성시에는

make cscope ARCH=<architecture name>


물론 <architecture name>은 그냥 아키텍쳐 이름만 써주면 된다. 예를 들어 arm을 분석한다면,


make cscope ARCH=arm


이렇게 해 주면 된다.

'리눅스 > 커널' 카테고리의 다른 글

__user  (0) 2012.07.01
__initcall(), module_init()  (0) 2012.07.01
Virtual Linux Manager 정리 1  (0) 2012.03.18
GCC, typeof  (0) 2012.02.23
Documentation/arm/booting  (0) 2011.09.25
Posted by code cat

1. Apache 2.0 라이센스를 다운 받는다. ()


2. NOTICE 에서 [] 안의 부분을 고친다.


Copyright [yyyy] [저작권자]


Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

 

3. 오리지널 copyright은 건들지 말고 냅두고, 코드에서 수정 부분이 있다면, 수정했다고 언급한다.(예 modified by CodeCat) 


4. 위의 NOTICE 를 아파치 라이센스가 적용되는 모든 파일에 커맨트형태로 넣는다.  


5. LICENSE 파일(1에서 다운받은) 과 NOTICE 파일(2에서 바꾼)을 프로젝트의 맨 위(root 폴더)에 넣는다.

 




'소프트웨어 엔지니어링' 카테고리의 다른 글

[용어] Payload란?  (0) 2014.07.18
[terminology] reap  (0) 2014.01.11
루틴: 루틴이름, 루틴길이,  (0) 2011.11.09
루틴: 설계  (0) 2011.11.09
Posted by code cat
프로그래밍2012. 4. 12. 10:24

출처: stackoverflow.com

콘솔상에서 간단하게 현재 상태가 진행 중 임을 알리는 progress animation이다.  우리가 흔히 카피중이거나 작업중에 볼 수 있는 형식이다.  정식으로는 쓰레드로 하나 돌리는게 맞겠지만, 어떻게 보면 프로세스가 무언가에 걸리고 있으면 애니메이션도 멈추는게 맞을지도 모르겠다.



실행하면 |,/,-,\, 를 반복한다.

Posted by code cat
리눅스2012. 4. 10. 15:43

다음의 글은 아래의 출처에서 가져왔음을 밝힌다.

출처:http://www.ibm.com/developerworks/kr/library/l-anatomy-ext4/



Linux 커널이 새롭게 발표될 때마다 몇 가지 뛰어난 기능이 포함되어 있듯이 이번 12월에 발표된 2.6.28 릴리스에도 우수한 기능이 포함되어 있다. 이 릴리스는 현재 개발 작업이 한창 진행 중인 Btrfs와 같은 여러 가지 우수한 기능 중에서 안정적인 ext4 파일 시스템이 최초로 적용된 릴리스이다. 이 차세대 Extended File System에서는 확장성과 신뢰성이 향상되었으며 뛰어난 새 기능도 추가되었다. Ext4는 1TB 디스크를 최대 백만 개까지 사용할 수 있는 파일 시스템으로 확장할 수 있다.

 

 

Extended File System의 약사


 

VFS(Virtual File System) 스위치

VFS는 상위 계층 파일 시스템 사용자의 기본 파일 시스템에 대한 세부 사항을 추상화하는 계층이다. 이러한 기능을 제공하는 VFS를 바탕으로 Linux는 지정된 Linux 시스템에서 여러 파일 시스템을 동시에 지원할 수 있다.

 

Linux를 지원하는 최초의 파일 시스템은 Minix 파일 시스템이었지만 이 파일 시스템에는 몇 가지 심각한 성능 문제가 있었기 때문에 Extended File System이라는 파일 시스템이 Linux를 위해 특별히 개발되었다. Remy Card가 설계한 첫 번째 Extended File System(ext)은 1992년 4월에 Linux에 채택되었다. ext 파일 시스템은 0.96c 커널에 구현된 VFS(Virtual File System) 스위치를 최초로 사용했으며 최대 2GB 크기의 파일 시스템을 지원했다.

 

두 번째 Extended File System(ext2) 또한 Remy Card가 구현했으며 1993년 1월에 발표되었다. 이 파일 시스템은 Berkeley FFS(Fast File System)와 같은 당시의 다른 파일 시스템의 발전된 아이디어를 채택했다. Ext2에서는 지원되는 파일 시스템의 크기가 2TB로 확장되었으며 2.6 커널에서는 ext2 파일 시스템의 최대 크기가 32TB로 확장되었다.

 

세 번째 Extended File System(ext3)은 일부 경쟁 파일 시스템에 비해 성능이 떨어지기는 했지만 Linux 파일 시스템의 맥락에서는 크게 발전한 모습을 보여 준 파일 시스템이다. ext3 파일 시스템에서는 예기치 않게 시스템이 중단되었을 때 파일 시스템의 신뢰성을 높여 주는 저널링 개념이 도입되었다. Silicon Graphics의 XFS 및 IBM® JFS(Journaled File System)와 같은 경쟁 파일 시스템의 성능이 더 좋기는 했지만 ext3은 이미 ext2를 사용하고 있는 시스템에서 직접 업그레이드할 수 있는 기능을 지원했다. Ext3은 2001년 11월에 발표되었으며 Stephen Tweedie가 구현했다.

현재, 네 번째 Extended File System(ext4)이 발표되었다. Ext4에는 성능, 확장성 및 신뢰성을 향상시킨 수많은 새 기능이 도입되었다. 가장 눈에 띄는 특징은 ext4가 1EB(exabyte)의 파일 시스템을 지원한다는 것이다. Ext4는 ext3를 유지 관리해 온 Theodore Tso가 이끄는 개발자 팀에 의해 구현되어 2.6.19 커널에 채택되었다. 그리고 지금은 2.6.28 커널에 이르러 안정적인 상태로 유지되고 있다(2008년 12월 현재).

Ext4에는 다양한 경쟁 파일 시스템의 유용한 개념이 적용되었다. 예를 들어, 익스텐트를 사용하여 블록을 관리하는 방법은 JFS에서 구현했으며 또 다른 블록 관련 기능인 지연된 할당은 XFS와 Sun Microsystems의 ZFS에서 구현했다.

새로운 ext4 파일 시스템에서는 혁신적으로 개선된 다양한 기능을 볼 수 있다. 새롭게 추가된 기능, 현재 파일 시스템의 한계를 뛰어 넘은 우수한 확장성, 오류에 효과적으로 대응할 수 있는 신뢰성 및 뛰어난 성능에 이르기까지 파일 시스템의 모든 부분에서 개선된 사항을 발견할 수 있다.


Ext4에는 새 기능이 매우 많이 포함되어 있기는 하지만 그 중에서도 가장 중요한 특징은 이전 버전인 ext3과의 쌍방 호환성이며 앞으로 더 높은 성능을 제공하게 될 미래의 Linux 시스템을 내다보고 시간 소인의 기능도 향상되었다.

이전 버전 및 후속 버전과의 호환성

ext3은 오늘날 Linux에서 가장 많이 사용되고 있는 파일 시스템 중 하나이기 때문에 ext4로의 마이그레이션은 큰 어려움 없이 쉽게 수행할 수 있어야 한다. 이를 위해 ext4는 쌍방 호환성을 고려하여 설계되었다(그림 1 참조). Ext4는 ext3 파일 시스템을 ext4 파일 시스템으로 마운트할 수 있도록 후속 버전으로의 호환성을 제공한다. ext4를 충분히 활용하려면 파일 시스템 마이그레이션을 수행하여 새로운 ext4 형식으로 변환한 후 사용해야 한다. ext4 파일 시스템을 ext3로도 마운트할 수 있기는(이전 버전과의 호환성) 하지만 ext4 파일 시스템에서 익스텐트(성능 섹션 참조)를 사용하지 않는 경우에만 가능하다.


그림 1. ext4의 쌍방 호환성

 


이러한 호환성 특징 외에도 ext3 파일 시스템을 ext4로 마이그레이션하는 작업을 점차적으로 수행할 수 있다. 즉, 옮기지 않은 기존 파일을 기존 ext3 형식으로 유지하면서 새 파일(또는 복사한 기존 파일)을 새로운 ext4 데이터 구조로 관리할 수 있다. 이러한 방법을 통해 온라인으로 ext3 파일 시스템을 ext4 파일 시스템으로 마이그레이션할 수 있다.

 

시간 소인 정밀도 및 범위 향상

 

놀랍게도 ext4 이전의 Extended File System에서는 초 단위의 시간 소인을 사용하고 있다. 이 시간 소인은 많은 설정에서 효과적으로 사용되었지만 프로세서의 처리 속도가 빨라지고 통합 기능(멀티 코어 프로세서)이 향상되었을 뿐만 아니라 고성능 컴퓨팅과 같은 다른 애플리케이션 도메인에서 Linux가 사용되면서 그 한계가 드러나고 있다. Ext4의 시간 소인은 기본적으로 나노초 LSB로 확장되어 후속 버전과의 호환성을 보장한다. 또한 두 개의 추가 비트를 통해 시간 범위도 500년 이후까지 사용할 수 있도록 확장되었다.


확장성

 

업그레이드할 파일 시스템의 가장 중요한 특성 중 하나는 증가하는 수요에 대응할 수 있는 확장성이다. 여러 가지 방법으로 확장성을 강화한 Ext4는 ext3 한계를 극복하고 파일 시스템 메타데이터 관리를 위한 토대를 새롭게 마련하였다.

 

파일 시스템 제한 확장

 

ext4의 첫 번째 가시적인 차이점은 파일 시스템 볼륨, 파일 크기 및 서브디렉토리 제한에 대한 지원이 향상되었다는 것이다. Ext4는 최대 1EB(1000PB)의 파일 시스템을 지원한다. 오늘날 적용되고 있는 표준에 따르면 많은 용량처럼 보이기는 하지만 스토리지 사용량이 지속적으로 늘어나고 있다는 점을 감안하면 ext4가 미래를 염두에 두고 개발되었음을 명확히 알 수 있다. ext4에서 허용되는 최대 파일 크기는 16TB(4KB 블록 가정)이며, 이는 ext3의 최대 파일 크기의 8배에 해당한다.

마지막으로 ext4에서는 서브디렉토리 제한도 32KB 디렉토리 깊이에서 거의 무한대로 확장되었다. 이러한 확장이 무리한 확장으로 보인다면 1EB의 스토리지를 사용하는 파일 시스템의 계층 구조를 생각해 봐야 한다. 디렉토리 인덱싱도 해시된 B 트리 형태의 구조로 최적화되었다. 따라서 제한이 크게 확장되었음에도 불구하고 ext4에서는 매우 빠른 조회가 가능하다.

 

익스텐트

 

ext3의 주요 단점 중 하나는 할당 방법에 있었다. 여유 공간에 대한 비트 맵을 통해 파일이 할당되었는데 이 방법은 빠르지도 않고 확장성도 좋지 않았다. Ext3의 형식은 작은 파일에 매우 효율적이지만 큰 파일에는 비효율적이다. Ext4에서는 할당 기능을 향상시키고 더욱 효율적인 스토리지 구조를 지원하기 위해 ext3의 메커니즘을 익스텐트로 대체했다. 익스텐트는 연속되는 블록 시퀀스를 나타낸다. 이처럼 익스텐트를 사용하게 되면 블록의 저장 위치에 대한 정보를 유지하는 대신 연속 블록으로 구성된 긴 목록의 저장 위치에 대한 정보가 유지되기 때문에 저장되는 전체 메타데이터의 용량이 줄어든다.

ext4의 익스텐트는 계층화된 접근 방법을 통해 작은 파일을 효율적으로 나타내며 익스텐트 트리를 사용하여 대용량 파일을 효율적으로 나타낸다. 예를 들어, 단일 ext4 inode에는 4개의 익스텐트를 참조할 수 있는 공간이 있으며, 이 경우 각 익스텐트는 연속 블록 세트를 나타낸다. 대용량 파일(조각화된 파일 포함)의 경우, inode는 인덱스 노드를 참조할 수 있으며, 각각의 인덱스 노드는 여러 익스텐트를 참조하는 리프 노드를 참조할 수 있다. 이 고정 깊이 익스텐트 트리는 대용량 스파스 파일에 대한 효과적인 표현 스키마를 제공한다. 또한 노드에는 파일 시스템 손상을 방지하기 위한 자동 검사 메커니즘이 있다.


성능

새 파일 시스템을 측정하는 데 사용되는 가장 중요한 속성 중 하나는 기본 성능이다. 성능은 가장 어려운 분야 중 하나이다. 왜냐하면 파일 시스템의 용량이 커지고 신뢰성에 대한 기대가 높아질수록 성능 저하가 발생할 수 있기 때문이다. 하지만 ext4는 확장성과 신뢰성을 제공하는 동시에 성능 향상을 위한 여러 가지 향상된 기능도 제공한다.

 

파일 레벨 사전 할당

 

데이터베이스 또는 컨텐츠 스트리밍과 같은 특정 애플리케이션에서는 드라이브에 대한 순차 블록 읽기 최적화를 사용하고 블록에 대한 읽기 명령 비율을 최대화하기 위해 연속 블록에 저장되는 파일을 사용한다. 연속 블록 세그먼트를 제공할 수 있는 익스텐트 외에도 과거에 XFS에서 구현되었던 대로 매우 큰 연속 블록 섹션을 원하는 크기로 사전 할당하는 매우 강력한 방법도 있다. Ext4에서는 지정된 크기의 파일을 사전 할당 및 초기화하는 새로운 시스템 호출을 통해 이 기술이 구현되었다. 그런 다음 필요한 데이터를 기록한 후 데이터에 대한 제한적인 읽기 성능을 제공할 수 있다.

 

블록 할당 지연

 

할당 지연은 파일 크기를 기반으로 하는 또 하나의 최적화 방법이다. 이 성능 최적화 방법은 블록을 디스크에 강제로 기록할 때까지 디스크의 물리적 블록을 할당하지 않고 기다린다. 이 최적화 방법의 핵심은 디스크에 기록할 필요가 있을 때까지 물리적 블록의 할당이 지연되기 때문에 더 많은 블록을 연속 블록에 할당 및 기록할 수 있다는 것이다. 이 방법은 파일 시스템에서 작업이 자동으로 수행된다는 점을 제외하면 지속적인 사전 할당과 유사하다. 하지만 파일 크기가 미리 알려져 있는 경우에는 지속적인 사전 할당이 가장 효과적인 방법이다.

 

멀티 블록 할당

 

최적화를 위해 향상된 마지막 기능은 ext4의 블록 할당자이다. 이 최적화 방법 또한 연속 블록과 관련되어 있다. ext3의 경우 블록 할당자는 한 번에 하나의 블록을 할당하는 방식으로 작동한다. 여러 개의 블록이 필요한 경우 연속 데이터를 연속되지 않은 블록에서 찾을 수 있었다. Ext4에서는 디스크에 연속되어 있을 수 있도록 여러 블록을 동시에 할당하는 블록 할당자를 사용하여 이 문제를 해결했다. 이전 최적화와 마찬가지로 이 최적화에서도 순차 읽기 최적화를 위해 디스크에서 최적화할 관련 데이터를 수집한다.

 

멀티 블록 할당의 또 다른 특징은 블록을 할당하는 데 필요한 처리 리소스의 용량에서 찾아볼 수 있다. 한 번에 하나의 블록만을 할당하는 가장 단순한 형태의 방법을 사용하는 ext3의 경우에는 블록 할당을 수행하기 위해 블록마다 한 번의 호출이 필요했다. 하지만 여러 블록을 동시에 할당하는 경우에는 블록 할당자에 대한 호출 횟수가 많이 줄어들기 때문에 할당 속도가 빨라지고 필요한 처리 리소스의 양도 줄어든다.


 

ext4에서는 파일 시스템이 매우 큰 크기로 확장될 수 있기 때문에 신뢰성에 대한 관심도 당연히 커질 것이다. Ext4에는 이러한 우려를 해소할 수 있는 여러 가지 자동 보호 및 자동 복구 메커니즘이 마련되어 있다.

 

파일 시스템 저널에 대한 체크섬 검사

 

ext3과 마찬가지로 ext4도 저널링 파일 시스템이다. 저널링저널(디스크의 연속된 영역에 있는 전용 순환 로그)을 통해 파일 시스템의 변경 사항을 기록하는 프로세스이다. 그런 다음 로그에 기록된 변경 사항에 따라 물리적 스토리지에 실제 변경 사항이 적용된다. 이 방법을 사용하면 좀 더 안정적으로 변경 사항을 구현할 수 있으며 작업 중에 시스템 오류 또는 전원 문제가 발생하더라도 일관성을 유지할 수 있다. 결과적으로 파일 시스템의 손상 가능성이 줄어드는 효과를 얻을 수 있다.

저널링을 사용하더라도 올바르지 않은 항목이 저널에 있다면 손상 가능성은 여전히 존재한다. 이 문제를 해결하기 위해 ext4에서는 저널에 대한 체크섬 기능을 구현하여 올바른 변경 사항만 기본 파일 시스템에 적용되도록 보장한다. 참고자료 섹션에서 ext4의 중요한 기능인 저널링에 대한 추가 참고자료를 볼 수 있다.

Ext4는 사용자의 필요에 따라 여러 가지 모드의 저널링을 지원한다. 예를 들어, ext4는 메타데이터만 저널링되는 모드(Writeback 모드), 메타데이터가 저널링된 후 저널을 바탕으로 메타데이터가 기록될 때 데이터가 기록되는 모드(Ordered 모드) 및 메타데이터와 데이터가 모두 저널링되는 모드(가장 안정적인 Journal 모드)를 지원한다. Journal 모드는 파일 시스템의 일관성을 보장하는 가장 좋은 방법이기는 하지만 모든 데이터가 저널을 통과하기 때문에 가장 느린 방법이기도 하다.

 

온라인 조각 모음

 

ext4에는 파일 시스템 내의 조각을 줄여 주는 기능(순차 블록 할당을 위한 익스텐트)이 통합되어 있기는 하지만 파일 시스템을 장기간 사용할 경우에는 어느 정도의 조각이 발생하는 것은 피할 수가 없다. 이 문제를 해결하여 성능을 향상시키기 위해 파일 시스템 및 개별 파일에 대한 조각 모음을 수행하는 온라인 조각 모음 도구가 제공된다. 온라인 조각 모음 도구는 인접한 익스텐트를 참조하는 새 ext4 inode에 파일을 복사하는 단순한 도구이다.

온라인 조각 모음의 또 다른 특징은 파일 시스템 검사(fsck)에 필요한 시간이 짧다는 것이다. Ext4에서는 inode 테이블에 있는 블록 그룹 중 사용되지 않고 있는 블록 그룹이 구별되기 때문에 fsck는 해당 블록 그룹 전체를 생략하여 빠르게 검사 프로세스를 수행할 수 있다. 파일 시스템의 크기가 증가하게 되면 필연적으로 내부 손상이 발생하기 마련이며 이러한 문제를 해결하기 위해 운영 체제는 파일 시스템에 대한 유효성 검증을 수행한다. 그리고 이러한 유효성 검증을 통해 ext4가 전반적으로 높은 신뢰성을 갖추고 있음을 알 수 있다.


미래의 모습

 

Extended File System은 분명 1992년에 처음 발표된 ext부터 2008년의 ext4에 이르기까지 Linux 내에서 길고도 의미 있는 역사를 가지고 있다. Linux를 위해 특별히 설계된 첫 번째 파일 시스템이면서 가장 효율적이고, 안정적이며 강력한 파일 시스템 중 하나였음을 입증해 보였다. XFS, JFS, Reiser 및 IRON 결함 허용 파일 시스템 기술 등의 다른 새 파일 시스템의 아이디어도 통합되어 있는 Ext4는 파일 시스템 관련 리서치에서 꾸준한 발전을 보여 주고 있다. 앞으로 개발될 ext5의 모습을 예측하기에는 너무 앞선 감이 있지만 엔터프라이즈 환경을 대비한 Linux 시스템을 이끌게 될 것이라는 점만은 분명하다.


참고자료

교육

제품 및 기술 얻기

  • kernel.org에서 최신 커널 릴리스를 다운로드할 수 있다.

  • developerWorks에서 직접 다운로드할 수 있는 IBM 시험판 소프트웨어를 사용하여 Linux와 관련된 후속 개발 프로젝트를 구현해 볼 수 있다.

토론

필자소개

M. Tim Jones

M. Tim Jones는 임베디드 펌웨어 아키텍트이자 Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming(현재 2판), AI Application Programming(현재 2판) 및 BSD Sockets Programming from a Multilanguage Perspective의 저자이다. 정지 위성을 위한 커널 개발에서 시작해 임베디드 시스템 아키텍처와 네트워크 프로토콜 개발에 이르기까지 다양한 분야에 대한 공학 지식을 가지고 있다. 콜로라도주 롱몬트 소재의 Emulex Corp.에서 컨설턴트 엔지니어로 활약하고 있다.

      


Posted by code cat
프로그래밍2012. 4. 8. 20:41

조엘 온 소프트웨어에서 나온 문제이긴 한데, 나도 인터뷰 때 저런 문제 풀어 본 적이 있어서, 이 정도는 스도코드로 몇분(그래 면접 때 떨리는데 머리가 팍팍 돌겠나..)안에 할 수 있어야 한다.  모르면 평소에 시간내서 풀어보자.

1. 원래 저장위치에서 문자열을 역순으로 변환하기

2. 연결 리스트를 역순으로 만들기

3. 한 바이트에서 1인 비트 세기

4. 이진 검색

5. 문자열에서 '연속적으로 문자가 반복되는 길이 run-length' 가 가장 긴 부분 문자열 찾기

6. atoi

7. itoa(스택이나 strrev를 써야 하기 때문에 좋은 문제임)

Posted by code cat