2016년 5월 21일 토요일

박싱 언박싱


   박싱
   참조형자료형인 object 에 struct 타입의 값을 대입했을때
   참조형인 object 는 struct 에 참조되는 값을 직접받을 수 없어
   struct 타입과 같은 인스턴스를 힙에 할당하고
   그 힙에 할당된 인스턴스를 참조한다.
   이는 참조가 끊기면 가비지가 된다.

먼저 메모리 구조를 좀 알아야 한다.

프로그램이 실행되기 위해서는 그 프로그램 내에서 사용되는 변수들을 위한 메모리가 할당되어야 한다.
프로그램이 실행되면 CPU는 그 프로그램을 위한 메모리를 할당한다.
메모리는 데이터의 성향에 따라 대개 4가지 영역으로 나뉘어져 프로그램에서 읽어드린 데이터들을 분류합니다.

그 4가지 영역은 코드 영역, 데이터 영역, 힙 영역, 스택 영역으로 나뉩니다.

1) 코드 영역

프로그램이 실행되면 모든 코드들이 이 코드 영역에 저장됩니다. 그리고 CPU가 와서 하나씩 차례로 실행합니다.

2) 데이터 영역

전역변수와 static 변수들이 저장됩니다. 즉, 이곳의 데이터들은 프로그램이 시작될 때 생겨나서 프로그램이 끝날때 까지 남아 있습니다.

3) 힙 영역

메모리 동적 할당 시 사용하는 공간입니다.

4) 스택 영역

지역 변수와 매개 변수가 할당됩니다.



int와 같은 자료형은 생성과 동시에 4byte라는 메모리가 할당되어야 한다.

하지만, string과 같은 자료형은 할당과 동시에 몇 바이트를 할당해야 하는지 알 수 없다.

따라서 int형으로 선언된 변수는 스택에 저장되고

string형으로 선언된 변수는 힙에 저장되는 것이다.

정확히 따지면,

int,byte,char,single,double,boolean,decimal과 같은 자료형들이 Value Type이고

String, Array, Object, Class, Interface, Delegate과 같은 자료형들이 Reference Type이라고 한다.


실제 메모리가 사용되는 과정을 보면서 더 잘 이해해보자.

예를 들어,

int a = 1;

이렇게 선언했다고 하자.
이렇게 된다는 말이다.

int형 변수에는 1과 같은 값이 저장된다.

즉, Value Type 변수에는 Value가 저장된다.


그렇다면,

string b = "bbbb";

이렇게 선언했다면?


이렇게 실제 값이 저장되어 있는 메모리의

주소를 가지고 있는 포인터를 가집니다.

실제 값을 가지고 있는 메모리의

참조를 가진다는 말입니다.

즉, Reference Type 변수는 Reference를 가집니다.






이런걸 왜 설명했을까요?

박싱(Boxing)이 바로 Value Type 변수를 Reference Type 변수로 바꾸는 과정이고

언박싱(UnBoxing)은 Reference Type 변수를 Value Type 변수로 바꾸는 과정이기 때문이다.


더 자세히 알아보도록 하자.

1. 박싱 (Boxing)


박싱은 힙에 Value Type을 저장하는 데 사용됩니다. 박싱은 Value Type을 object형식(Reference Type) 또는 이 Value Type에서 구현된 임의의 인터페이스 형식으로 변환하는 암시적 변환입니다. Value Type을 박싱하면 힙에 오브젝트 인스턴스가 할당되고 값이 새 오브젝트에 복사됩니다.

int i = 123;

//박싱 연산한다.
object o = i;

이 코드의 결과로 힙에 있는 int 형식의 값을 참조하는 o 오브젝트가 스택에 생성됩니다. 이 값은 변수i에 할당된 Value Type 값의 복사본입니다. 다음 그림에서는 두 변수 io의 차이점을 보여 줍니다.

다음 예제에서와 같이 명시적으로 boxing을 수행할 수도 있지만 명시적 boxing이 반드시 필요한 것은 아닙니다.

(궁금한 점 : O는 Reference 타입이므로 힙 영역에 저장되어야 하는것 아닌가??)
int i = 123;

object o = (object)i;

근데 만약 i값을 바꿔준다면 어떻게 될까?
o에 저장된것은 힙 영역에 있는 오브젝트의 참조이다.

이 오브젝트는 i가 저장하고 있는 값의 복사본을 저장하고 있다.

즉, i와 직접적으로 연결되어 있는 것이 아니라, 단지 i의 값을 복사해서 가지고 있을 뿐이므로

i값에는 영향을 미치지 않는다.


2. 언박싱(UnBoxing)


unboxing은 object 형식(Reference 형식으로 봐도 무방할듯)에서 값 형식으로, 또는 인터페이스 형식에서 해당 인터페이스를 구현하는 값 형식으로의 명시적 변환입니다. unboxing 연산 과정은 다음과 같습니다.
  • 오브젝트 인스턴스가 지정한 Value Type을 boxing한 값인지 확인합니다.
  • 인스턴스의 값을 Value Type 변수에 복사합니다.
다음 문은 boxing 및 unboxing 연산을 모두 보여 줍니다.

int i =123;

object  o = i;   // 박싱

int j = (int)o;  // 언박싱

런타임(프로그램이 실행되고 있는 동안)에 특정 Value Type의 언박싱이 성공하려면 언박싱되는 항목(이 경우에는 o)은 이전에 해당 Value Type의 인스턴스를 boxing하여 생성된 개체의 주소값을 가리키는 참조여야 합니다.
null(어떠한 주소값도 없을 경우)을 unboxing하려고 하면 NullReferenceException이 발생합니다.
호환되지 않는 값 형식에 대한 참조를 unboxing하려고 하면 InvalidCastException이 발생합니다
(위 예에서 j의 자료형이 float이거나 double이면 InvalidCastException이 발생한다는 말이다.)

예제

다음 예제에서는 잘못된 unboxing의 경우와 그 결과로 발생하는 InvalidCastException을 보여 줍니다.
이 예제에서는 trycatch를 사용하여 오류가 발생할 때 오류 메시지를 표시합니다.

이 프로그램의 출력은

Specified cast is not valid. Error: Incorrect unboxing.

다음 코드를

int j = (short)o;

다음 코드로 바꿔야한다.

int j = (int)o;

3. 왜 박싱과 언박싱을 할까?


4. 정리

C++과 C#의 차이 - 작성완료

C++ / C#
   구조체와 클래스 차이
  
   CPP
   기본 접근 제한자가 class private, struct public
   
   C#
   구조체 가비지 대상아님
   구조체 정적 바인딩
   구조체 대입시 값의 복사가 됨
   용량이 작고 임시적으로 쓰는 데이터를 구조체로 만드는 것이효과적
   다른 구조체의 상속은 안되지만 인터페이스 상속은 된다.
   (cpp 싱글포인터라고 생각하면 반먹고 들어감)
   클래스 참조 자료형
   동적바인딩으로 만들어진 힙에할당된 인스턴스를 참조하는 방식
   클래스간의 대입시 인스턴스의 참조값이 대입됨

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

  • C++과 C#의 차이점 #1: 선행처리기의 지시어로 #include가 없습니다. Java import와 비슷하게 using 이라는 키워드를 써서 library 에 있는 class 들을 쓸 수 있습니다. 나름대로 그 역할에 충실했던 선행처리기는 자신의 문제점과 함께 갈수록 기능이 줄어 드는 것 같습니다. 그렇지만 C#에서는 Java와 달리 conditional compiler을 위한 지시어들은 계속 지원하는 것 같습니다. 방준영님의 글에 따르면 "C++와의 차이점이라면 선행처리기가 컴파일러 안에 통합되어 있다는 것"이 라네요. 컴파일된 object 자체에 풍부한 metadata 가 포함되어 있다는 의미겠죠. 그렇게 되면 object 파일이 어쩔 수 없어 커진다는 문제도 있습니다. 이건 Embedded System 용으로는 치명적인 약점이 될 수도 있을 것입니다(Java C# CSharp cpp 프로그래밍언어 비교 선행처리기)

    • C++와 C#의 차이점 #2: Java Byte Code와 비슷하게 IL(Intermediate Language)라는 중간 코드가 있습니다. IL은 Java Byte Code와는 다르게 여러 프로그래밍 언어를 지원하네요. VB, C#, C++ 등. 홍민희님이 그러시는데, JScript.NET, Boo, F# 등이 있다고 하네요(프로그래밍언어 C# C++ Java 비교 중간언어 cpp CSharp)2008-07-08 23:23:07
    • C++와 C#의 차이점 #3: Application을 의미하는 클래스가 꼭 있어야 합니다. 프로그램 진입점이 ApplicationClass.Main() 이네요. Java는 ApplicationClss.main() 인데… 마치 대학교때 친구 숙제 베껴서 낼 때 변수 이름만 바꾼 듯한 느낌이 드는 것은 저만의 느낌일까요 ? (프로그래밍언어 C# C++ Java 비교 cpp CSharp 프로그램진입점)2008-07-08 23:26:33
    • C++와 C#의 차이점 #4: Array가 단순 메모리 공간이 아닌 부가정보를 가진 객체입니다. 즉, 간단한 예로, array.Length 이런게 먹힌다는 거죠. Java 랑 정말 비슷합니다. C에서처럼 array의 element 개수를 주고 받느라 귀찮게 함수 형식인자 하나 더 쓸 필요가 없다는 것이고, C++에서처럼 element 개수를 가지고 있는 array class를 정의할 필요도 없다는 것이죠. 또는 vector 를 쓸 때처럼 초기화할 때 불편하게 초기화할 필요도 없겠죠. 초기화 방식이 built-in type 하고 똑같으니까요. 물론 최근 c++0x에서는도 언어수준에서 vector 같은 클래스에 대해 uniform initialization 이 가능하게 하려고 하고 있긴 하죠(프로그래밍언어 C# C++ Java 비교 cpp CSharp array)2008-07-08 23:30:26
    • int[] ia = { 100 }; System.Console.WriteLine(ia[2]); 했더니 “처리되지 않은 예외: System.IndexOutOfRangeException: 인덱스가 배열 범위를 벗어났습니다”라는 run-time exception이 발생하네요. 이 얘기는 array access 할 때마다 range check 를 한다는 얘기인데… bug 를 막는데는 도움이 되겠지만 성능에는 좋지 않을 것입니다. 언어의 설계 철학을 느낄 수 있는 대목입니다.
    • C++와 C#의 차이점 #5: 설계 철학이 다릅니다(프로그래밍언어 C# C++ Java 비교 cpp CSharp 설계철학)2008-07-08 23:37:47
    • C++는 꼭 쓸사람만 비용을 부담하게 하자는 주의이고(수익자 부담의 원칙이랄까...), C#은 Modern Language 답게 비용이 부담되더라도 버그가 생길 여지를 아예 없애자라는 주의입니다. 요즘 같이 CPU 성능이 갈수록 좋아지는 때에는 Java 나 C# 같은 언어가 좋게 느껴질 수도 있지만 여전히 아주 다양한 Embedded System 에 쓰기는 무리일 것입니다. 세상은 우리가 생각하는 것보다 우리가 경험한 것보다 훨씬 다양하고 다채롭죠.
    • C++와 C#의 차이점 #6: sbyte, short, int, long, byte, ushort, uint, ulong, float, double, decimal, bool기본 데이터 타입의 크기가 표준화되어 있습니다. 이건 참 맘에 든다. C++도 이렇게 표준화 됐었으면 좋으련만. 그럼 프로젝트 할 때마 OSAL에 int8, int16, int32, int64 이딴거 정의 안해도 될텐데 말입니다.(프로그래밍언어 C# C++ Java 비교 cpp CSharp 기본데이터타입)2008-07-08 23:44:01
    • C++와 C#의 차이점 #7: 상속 계층의 꼭대기에 언어 수준의 object(Java 에서는 Object) 라는 class가 있습니다. 방준영님의 글에 따르면 "엄밀히 구분하면 object는 C#의 키워드고 실제 클래스명은 자바와 같이 Object다"라고 하네요. 각종 언어 수준의 작업을 일관된 인터페이스로 해주는 녀석이겠죠. 이것도 type system에 구멍이 생길 수 있어서 논란의 여지가 있습니다. 저에게는 object 는 마치 C++의 void * 같은 녀석처럼 보이네요. ^^(프로그래밍언어 C# C++ Java 비교 cpp CSharp 상속계층꼭대기기본클래스 object)2008-07-08 23:55:55
    • C++와 C#의 차이점 #8: 문자열 리터럴이 char * 가 아니라 언어 수준의 utf-16(Java 에서 String 은 utf-8 이던가요 ? 방준영님의 글에 따르면 "자바도 C#과 마찬가지로 String 타입이 UTF-16이다"라고 하네요.) 유니코드 문자열 클래스인 string의 인스턴스이다. “hello” 라고 하면 내부적으로 적어도 10 bytes 가 할당되겠네. 메모리가 싼 요즘엔 별 이슈는 안되겠다.(프로그래밍언어 C# C++ Java 비교 cpp CSharp 문자열리터럴 string)2008-07-09 00:04:57
    • C++와 C#의 차이점 #9: C++와 달리 pointer 사용에 제약이 있는 것 같다(이건 정확한 게 아니라서 나중에 더 확인하고 정리해 보겠습니다). 큰 장점이자 단점이 될 수 있겠지. 그런데 이제 단점으로 작용하는 영역이 별로 클 것 같진 않다. OS나 Device Driver 에서나 쓰기 어렵지 다른 곳에서 웬만하면 쓰일 수 있을테니까. 방준영님의 글에 따르면 "C#에도 포인터가 있다. C#으로 만든 OS도 있다"고 하네요.(프로그래밍언어 C# C++ Java 비교 cpp CSharp pointer 포인터)2008-07-09 00:10:38
    • C++와 C#의 차이점 #10: C++의 struct 는 또다른 class 이지만 C#의 struct 는 힙에 할당할 수도 없고, 상속 관계를 쓸 수도 없습니다. 무조건 object 에서 직빵으로 상속받는군요. 그리고 default accessibility 는 private 이네요(C++에서는 public 이죠)(프로그래밍언어 C# C++ Java 비교 cpp CSharp struct)2008-07-09 00:30:56
    • 아주 간단한 concrete object 를 정의할 때나 써 먹는 게 낫겠습니다. 힙에 할당도 안되고, reference로 가리킬 수도 없고 값 형식만으로만 쓰기 때문에 큰 객체는 정의할 꿈도 꾸지 않는게 낫겠네요
    • new 로 할당하더라도 heap에 할당되는 게 아니라 스택에 할당됩니다. 그리고 모든 연산에 대해 항상 값 자체를 리턴합니다. matrix 를 struct 로 정의하면 모든 연산을 할 때마다 stack 안에서 엄청난 임시 객체들이 만들어지고, 계속해서 객체 복사가 일어난다는 뜻입니다. 허걱! struct를 써서는 각종 optimize 를 할 수가 없다는 뜻이겠죠. 웬만하면 class 를 써야겠네요.
    • C++와 C#의 차이점 #11: C#의 class 는 단일 상속만 허용됩니다. 그리고, 멤버 변수 및 멤버 함수 외에 속성, 인덱서, 이벤트 등의 멤버가 있고, access 도 internal, protected internal 이 있습니다. Java와 같이 interface 를 따로 뒀으니 단일 상속으로 해도 별로 문제 될 것 같진 않습니다(프로그래밍언어 C# C++ Java 비교 cpp CSharp 클래스 class)2008-07-09 00:46:52
    • C++와 C#의 차이점 #12: C#에서 함수 매개 변수 선언시에는 값 매개 변수 외에 참조 매개 변수(ref 키워드 사용), 출력 매개 변수(out 키워드 사용)를 지정할 수 있습니다.(프로그래밍언어 C# C++ Java 비교 cpp CSharp 매개변수)2008-07-09 00:51:28
    • 그리고 params 라는 키워드로 매개 변수를 배열로 지정할 수 있는데… 그건 C/C++에서 매개변수에 대해 '...'이라고 표시하고 함수 implementation 안에서는 va_arg 를 쓰는 것과 비슷합니다. 단지 매개 변수 배열로 넘기면 마치 array 쓰듯이 할 수 있다는 점이 다르겠죠. 단순 syntactic sugar 라고 생각됩니다.
    • 함수의 signature 에는 ref, out 키워드가 붙어 있는지의 여부도 포함됩니다. 단, ref, out 만다른 함수 overload 는 불가능합니다.
    • C++와 C#의 차이점 #13: 초기화되지 않은 지역 변수를 사용하려고 하면 컴파일러 에러(경고가 아니라!!!)가 발생한다.(프로그래밍언어 C# C++ Java 비교 cpp CSharp 지역변수 초기화)2008-07-09 00:59:27
    • 초보 프로그래머들이 저지르기 쉬운 실수를 미연에 막아준다. 좋은 특징이라고 생각됩니다. out 과 ref 를 구분해서 초기화되지 않은 경우를 컴파일러가 쉽게 알아낼 수 있도록 한 것도 눈에 띄네요. 똑똑한 것들!
    • C++와 C#의 차이점 #14: 가상 함수와 순수 가상 함수를 나타내는 키워드를 분리했습니다. 가상 함수는 virtual, 순수 가상 함수는 abstract! subtype 이 override 할 때는 override 라는 키워드를 써야 합니다. 순수 가상 함수는 interface 와 기능이 겹칠 것 같은데… 왜 class 에서도 중복해서 지원할까? 단일 상속 제약때문에 그럴까요 ? 방준영님의 글에 따르면 "인터페이스가 있는데도 굳이 순수 가상 함수를 둔 이유는 일부 함수는 상위 클래스에서 미리 구현하고 일부 함수는 하위 클래스에 구현을 맡기는 형태의 디자인이 가능하기 때문. 반대로 정말 순수하게 순수 가상 함수로만 이루어진 클래스를 만든다면 인터페이스를 쓰는 쪽이 훨씬 깔끔하다"라고 하네요.(프로그래밍언어 C# C++ Java 비교 cpp CSharp 가상함수)2008-07-09 01:10:33
    • C++와 C#의 차이점 #15: 형식 매개 변수의 형태로 template과 같은 기능을 제공합니다. C#용어로는 지네릭이라고 합니다. C++처럼 강력한 generic programming 이 가능한지는 모르겠지만. 그리고, template이란 키워드를 사용하지 않고 <> 안에 형식 매개변수만 나열하면 됩니다(프로그래밍언어 C# C++ Java 비교 cpp CSharp template)2008-07-09 01:15:30
    • C++와 C#의 차이점 #16: 클래스의 event 멤버는 signal/slot 기능을 언어 수준에서 제공해주는 것입니다. event는 delegate와 연결됩니다. Boost.Signal library 처럼 type safe signal/slot 기능을 제공해 줍니다. event 멤버를 정의하면 +=, -= 을 이용해서 event handler 를 등록하고 제거할 수 있습니다.(프로그래밍언어 C# C++ Java 비교 cpp CSharp class event member delegate)2008-07-09 01:26:13
    • C++와 C#의 차이점 #17: C++의 RAII idiom은 using 문으로 구현할 수 있습니다. using (resource 초기화) { // 실행 코드 } 이런식으로 작성하시면 됩니다.(프로그래밍언어 C# C++ Java 비교 cpp CSharp using구문 코드 블록)2008-07-09 01:32:35
    • C++와 C#의 차이점 #18: loop construct 로 foreach도 있습니다. int[] ia = {1,2,3}; foreach (int e in ia) { … } 이런게 가능합니다. c++0x 에서도 비슷한 기능을 도입하려고 하고 있죠(프로그래밍언어 C# C++ Java 비교 cpp CSharp foreach)2008-07-09 01:35:42
    • C++와 C#의 차이점 #19: scope operator 가 '::' 이 아니라 '.' 입니다. 전 이게 더 좋은 것 같아요. 어떤 경우는 :: 을 쓰고 어떤 경우는 . 을 쓰고 그랬는데, 이렇게 하나로 통일하는 게 좋은 것 같네요

    링크드 리스트와 배열의 차이 - 작성완료

    Stl Vector List 설명
       장단점
       간혹 둘중에 하나 그자리에서 짜보라고함

    --------------------------------------------------------------------------------------------------------------

    1. vector일반적인 배열처럼 vector는 개체들을 연속적인 메모리 공간에 저장한다.
    즉, iterator 뿐 아니라 position index(operator [])로도 접근이 가능하다는 것이다.

    vector는 동적으로 확장/축소가 가능한 dynamic array로 구현되어 있다.

    강점
    • 개별 원소들을 position index로 접근이 가능하다 (상수 복잡도)
    • 원소를 컨테이너의 끝에 삽입/제거 하는 것이 빠르다 (상수-아모타이즈드 복잡도)
    • 어떠한 순서로도 원소들을 순회할 수 있다. 즉, Random access iterating이 가능함. (로그 복잡도)
    일반적으로 vector는 다른 두 개의 시퀀스 컨테이너인 deque, list에 비해 개별 원소에 대한 접근 속도와 컨테이너의 끝에서 삽입/제거하는 속도가 가장 빠르다.
    굳이 "일반적으로" 빠르다는 표현을 쓴 것은 특정 상황별로 달라지기 때문이다.
    이는 아래 내용들을 모두 읽어보고 종합적으로 분석해 보면 알 수 있다.

    약점
    • 컨테이너의 끝 위치가 아닌 곳에서 삽입/제거 수행시 그 성능은 deque/list에 비해 현저히 떨어진다.
    주의
    • 동적으로 컨테이너의 크기가 확장/축소되는 것이 편하기는 하나, 확장시의 reallocation은 비용이 꽤 크다.
    • capacity를 확장 시켜줄 수 있는 적절한 크기의 reserve로 인한 메모리 확보가 중요.


    2. deque
    (double ended queue)

    deque는 어느 정도 vector와 유사성이 있는 듯하면서도 상당히 많이 다르다고도 할 수 있는 시퀀스 컨테이너다.

    우선, Random access iterator를 통한 개별 원소에 대한 접근이 가능하다. operator []도 지원된다.
    그리고, 컨테이너의 크기 역시 동적으로 조절되지만, 그 방법은 vector의 그것과 많이 다르다.

    강점
    • 개별 원소들을 position index로 접근이 가능하다.
    • 원소를 컨테이너의 끝 뿐 아니라, 앞에서도 삽입/제거 하는 것이 빠르다.
    • 어떠한 순서로도 원소들을 순회할 수 있다.
    약점
    • 컨테이너의 시작 / 끝 위치가 아닌 곳에서 삽입/제거 수행시 그 성능은 list에 비해 현저히 떨어진다.

    vector와 비슷해 보이지만, 두번째 강점이 vector와의 첫번째 차이점이다.
    vector는 컨테이너 끝에 삽입/제거하는 것만이 빨랐지만, deque는 컨테이너 끝 뿐 아니라 처음부분에서의 삽입/제거도 효율이 높다. double ended 라는 naming...

    이러한 특징으로 STL의 스택과 큐 클래스는 deque와 list로 구현이 가능하지만, 기본 클래스는 deque이다.

    그리고 vector와의 두번째 차이점이 컨테이너의 동적 확장/축소 방식이다.
    이는 어떻게 보면 deque의 불편한 점이 되기도 하고, vector보다 더 나은 점이 되기도 한다.

    vector의 경우 컨테이너 내부 capacity가 고갈되면 이를 확장하기 위해 전체 메모리 크기만큼 reallocating이 발생한다.
    하지만, deque의 경우 일정 크기를 가지는 chunk 단위로 확장되는 방식을 가지고 있다.
    이렇기에 vector에 비해 다음과 같은 장단이 존재한다.

    장점
    • 저장 원소가 많고 메모리 할당량이 큰 경우 vector에 비해 확장 비용이 절감된다.
      : 전체가 재할당되기 보다, 늘어나야 될 크기만큼만의 chunk가 하나 더 할당되면 그만이므로...
    단점
    • 컨테이너 처음부터 끝까지 연속 메모리 공간이 아니므로, vector에서 가능했던 원소들간 포인터 연산이 불가능하다.


    3. list

    list는 doubly linked list로 구현되어 있다.

    강점
    • 컨테이너의 어느 위치에서도 삽입/제거가 빠르다 (상수 복잡도)
    • 원소들의 컨테이너 내 순서 이동이 빠르다. (상수 복잡도)
    vector와 deque와 다르게 list의 가장 큰 강점은 컨테이너 내 어느 위치에서도 원소의 삽입/제거가 빠르다는 것이다.

    약점
    • 원소의 position index로 직접 접근이 불가능하다.
      : 특정 원소에 접근하려면 처음이나 끝에서부터 선형 탐색을 하여야만 한다.
    • 컨테이너 내 원소 순회는 forward / reverse 순회만 가능하며, 느리다. (선형 복잡도)
    • 원소들간 상호 연결 정보를 위해 추가적인 메모리가 사용된다.
      : 원소 수가 적을수록 그 상대 비율은 올라가겠지 쩝;
    얼핏 보면 약점이 되게 많아 보이지만, 컨테이너 내 어느 위치에서도 원소의 삽입/제거가 빠르다는 장점이 list의 활용성을 대변해 주는 키워드이다.

    패딩비트 ( struct ) - 작성 완료

    출처 - http://bboy6604.tistory.com/entry/%EA%B5%AC%EC%A1%B0%EC%B2%B4%EC%99%80-Padding-Bit

    구조체는 서로 다른 타입의 변수들을 묶어서 새로운 자료형으로 정의 하는 것입니다.
    구조체에는 변수, 배열, 포인터,다른 구조체를 포함 할 수 있습니다.

    Padding Bit

    구조체의 크기는 구조체 안의 변수들을 합한 결과가 아니다.
    다음의 코드를 보자.

    struct st

    {

         int     a;

         char  b;

         short c;

         char  d;

         int     e;

    }

    int형 2개 8byte,  char형 2개 2byte,  short형 1개 2byte,
    총 11byte 이다.
    하지만 sizeof 연산자를 통해크기를 출력하면 16byte가 나온다.
    이것은 cpu 가 성능 저하를 막기 위해 넣어준 Padding Bit 때문이다.

    32 bit cpu 가 데이터를 효율적으로 읽어 들이려면 32 bit 로 읽어야 한다.
    그 이하면 필요없는 부분을 읽지 않는 작업을,
    그 이상을 읽으면 32bit를 추가하고 나머지를 읽지 않는 작업을 해야한다.
    이 과정에서 성능 저하가 일어난다.

    그래서 구조체 변수를 읽어 올 때는 컴파일러가 성능 저하를 막기 위해 Padding bit 라는 것을 자동 추가 해준다. ( Padding bit 를 추가해주지 않는 컴파일러도 있다.)
    Padding bit 가 추가되는 모습은 아래와 같습니다. (파란색 부분이 Padding bit 입니다.)


    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    4A
    4B
    4C
    4D
    4E
    4F
    a
    b
     
    c
    d
     
     
     
    e
    4byte
    4byte
    4byte
    4byte

    Padding bit 만큼 메모리를 낭비 되지만
    32 bit 단위로 데이터를 읽어오면 되어 속도는 빨라진다.

    Padding bit 는 컴파일러가 자동으로 추가 하는 것이기 때문에 사용자가 사용하지 않을 수있다. #pragma pack(1) 으로 전처리에 명령을 내리면 구조체를 1byte 단위로 읽기 때문에 구조체 구성 변수를 더한 값이 구조체의 크기가 된다.

    하지만 #pragma 는 C 표준이 아니기 때문에 이식성이 낮다. 혼자만 쓰는 프로그램이면 #pragma 를 사용해도 크게 문제가 되지 않는다.
    하지만 이 프로그램이 통신에 쓰인다면 치명적인 문제점을 안게 된다.
    또 한 #pragma pack(1) 이라고 선언해주면 선언 이후의 코드들을 전부 1byte 단위로 데이터를 읽기 때문에 엄청난 성능저하를 가져오게 된다.
    이러한 성능 저하를 막기 위해 우리가 1byte 씩 읽어오기를 원하는 코드 전에서 #pragma pack(1)을 선언해주고 그 코드의 끝 부분에 다시 #pragma pack(4) 로 선언해주면 된다. 위의 코드에 적용해보면 다음과 같게 됩니다.



    #include <stdio.h>
    #pragma pack(push,1);

    struct st
    {
      int a;
      char b;
      short c;
      char d;
      int e;
    };

    #pragma pack(4);

    int main(void)
    {
      struct st st1;
      printf("구조체의 크기: %d\n",sizeof(st1));
      printf("a의 주소: %p, b의 주소: %p, c의 주소: %p, d의 주소: %p, e의 주소 : "
          "%p",&st1.a,&st1.b,&st1.c,&st1.d,&st1.e);

      return 0;
    }

    하지만 이처럼 수정해주면 32 bit cpu에서는 괜찮지만 8 bit 나 16bit 또는 64 bit cpu 에서 다시 문제가 야기됩니다.
    이때는 다음과 같이 해주면 됩니다.


    #include <stdio.h>
    #pragma pack(push,1);

    struct st
    {
      int a;
      char b;
      short c;
      char d;
      int e;
    };

    #pragma pack(pop);

    int main(void)
    {
      struct st st1;
      printf("구조체의 크기: %d\n",sizeof(st1));
      printf("a의 주소: %p, b의 주소: %p, c의 주소: %p, d의 주소: %p, e의 주소 : "
          "%p",&st1.a,&st1.b,&st1.c,&st1.d,&st1.e);

      return 0;


    #pragma pack(push, 1) //1byte 단위로 정렬 방식을 바꾸고 기존정렬방식을 스택에 저장합니다.
    #pragma pack(pop)       //스택에 저장한 정렬방식으로 다시 돌립니다.
    pack 지시자는 이 후 부터 선언되는 구조체의 정렬 방식을 지정하는 것입니다.
    1은 컴파일러가 저장된 메모리에 데이터를 정렬하는 방법을 결정하는 byte의 크기입니다.




    Little Endian, Big Endian - 작성완료

    출처 - http://firejune.com/1790/%EB%B9%85%EC%97%94%EB%94%94%EC%95%88%EA%B3%BC+%EB%A6%AC%ED%8B%80%EC%97%94%EB%94%94%EC%95%88+%EA%B0%9C%EB%85%90

    컴퓨터에서 어떤 크기의 데이터를 메모리에 저장할 때 바이트 단위로 나누어 저장합니다. CPU 아키텍처에 따라 바이트 저장순서가 달라질 수 있기 때문에 두 가지로 나뉘는 데 그것이 바로 '리틀-엔디안'과 '빅-엔디안' 방식입니다. 어떤 CPU에서는 이 두 가지 방식을 모두 지원하도록 구성할 수도 있답디다.

    리틀-엔디안 (Little-Endian)

    낮은(시작) 주소에 하위 바이트부터 기록, Intel CPU 계열
    예) 32비트형 (4바이트) 값: 0x01020304

    하위 주소0x040x030x020x01상위 주소

    빅-엔디안 (Big-Endian)

    낮은(시작) 주소에 상위 바이트부터 기록, Sparc / RISC CPU 계열
    예) 32비트형 (4바이트) 값: 0x01020304

    하위 주소0x010x020x030x04상위 주소

    빅엔디안은 우리가 평소에 보던 방식으로 메모리에 쓴다고 생각하면 되고 리틀엔디안은 뒤집혀서 쓴다고 이해하면 되겠죠? 그럼 왜 빅엔디안으로 안 쓰는 걸까요? 그 이유는 산술연산유닛(ALU)에서 메모리를 읽는 방식이 메모리 주소가 낮은 쪽에서부터 높은 쪽으로 읽기 때문에 산술 연산의 수행이 더 쉽습니다. 또한, 데이터를 다른 시스템으로 전송할 때 서로 다른 데이터 저장 방식의 시스템끼리 통신하게 되면 전혀 엉뚱한 값을 주고받기 때문이랍니다.

    UDP와 TCP 차이 - 작성완료



    1. TCP 연결-지향형 통신이고, UDP 비연결형 통신이다.
    TCP 통신 종단점으로 자료를 전송하기 위해 먼저 클라이언트가 연결 요청 메시지를 보내고, 서버는 이를 수락한다. 일단 클라이언트와 서버 간의 연결이 맺어지면 각각 표준 read, write 함수를 이용하여 대칭적 양방향 통신을 사용한다. 종단점에는 클라이언트와 서버가 존재한다. 양단 모두에서 연결을 닫을 있고, 경우 다른 쪽은 읽기와 쓰기 명령 시에 이를 감지한다. 따라서 TCP 통신을 사용하는 애플리케이션은 언제 작업이 완료되었는지를 원격지로 알릴 있다.
    반면 다수를 대상으로 자료를 전송하고 받는 애플리케이션은 UDP 사용한다. 메시지들은 대상 주소를 포함하고 있어야 한다. UDP 원격지의 실행 유무를 애플리케이션에 알랄 없다.

    2. TCP 바이트 스트림 기반이고, UDP 메시지 기반이다.
    애플리케이션이 번의 sendto 함수를 이용하여 UDP 메시지를 전달하면, 반대편 종단점은 recvfrom 호출하여 메시지 전체를 가져오거나 그렇지 못할 것이다.
    반대로 번의 TCP write 이용하여 데이터 블록을 전송하는 애플리케이션은 수신 측이 번의 read 통해 전체 데이터를 읽을 있다는 점을 보장하지 않는다. 번의 read 명령은 연속된 바이트를 스트림의 형태로 가져온다.
    과정은 데이터 블록의 전체 혹은 부분일 있고, 여러 데이터 블록일 있다.

    3. TCP 전송한 순서에 맞게 바이트 스트림을 전송한다. UDP 네트워크 상의 에러가 없다는 가정을 하더라도 전송된 순서와 상관없이 메시지를 받는다. UDP 받은 순서대로 애플리케이션에 메시지를 전달한다. UDP 패킷은 인터넷 상에서 각각 다른 통신로를 따라 전달될 있기 때문에 보내진 순서대로 도착하지 않을 있다. 반대로 수신 호스트의 네트워크 하부 시스템은 TCP 패킷을 버퍼에 저장하고, 애플리케이션에게 전송된 순서에 맞게 메시지를 전달하기 위해 순서 번호를 사용한다.

    4. TCP 신뢰할 있고, UDP 신뢰할 없다. 만약 TCP 원격지로 데이터를 전송할 없다면 에러를 리턴하여 실패 여부를 알린다. UDP 그렇지 못하다. 네트워크에서 UDP 패킷이 손실될 있고, 경우 메시지는 절대 원격지로 전달되지 않는다. UDP 수신 측과 송신 측에게 에러가 발생되었다는 사실을 알릴 없다.

    5. UDP sendto 함수와 TCP write 함수는 보낼 메시지를 호스트의 네트워크 하부 시스템 버퍼로 복사한 리턴한다. UDP 리턴은 수신 측의 상태와 무관하게 이루어진다. 반면 TCP 리턴은 어느 정도 수신 측과 네트워크의 상태에 의존한다. TCP 네트워크 하부 시스템은 수신 호스트가 확인 패킷을 보내지 않음으로써 수신 측에 충분한 버퍼가 없다고 인지하거나 네트워크 트래픽이 혼잡할 있기 때문에 전송할 데이터를 버퍼에 보관할 있다. 보관된 데이터로 인해 실행되는 write 함수가 블록될 있다. TCP 프로토콜이 제어를 하더라도 TCP write 함수의 리턴을 데이터가 원격 호스트로 전송되었다는 것으로 해석하지 말아야 한다.

    --------------------------------------------------------------------------------------------------------------------------]

    TCP와 UDP 프로토콜 (서술형)

    소켓통신에는 기본적으로 2가지의 통신방법이 있다. 신뢰성 프로토콜인 TCP(Transfer Control Protocol)와 비신뢰성 프로토콜인 UDP(User Datagram Protocol)가 그것입니다.

    (1) TCP 통신의 개념
      : TCP(Transmission Control Protocol) 통신은 전화와 같은 방식으로 동작한다.

    보통의 경우 상대방의 전화번호를 알고 있어야 전화를 거는 것처럼 TCP 통신을 하기 위해서는 상대방의 IP 주소와 Port를 알고 있어야 연결을 요청할 수 있습니다. 그리고 전화를 걸더라도 받아주지 않으면 계속해서 대기해야 합니다. 이와 마찬가지로 서버가 응답을 받아주지 않으면 계속적으로 요청을 하게 됩니다. 물론 어느 순간에 포기하는 것도 마찬가지입니다.

    만약 전화를 받았다고 생각해 보자. 양방향 통신이 가능하다. 한번 연결되면 계속해서 상대방에게 음성을 전달할 수 있는 것처럼 TCP 통신에서도 계속적으로 소켓을 통해서 데이터를 주고 받을 수 있다.

    전화가 연결된 후 끊기 전까지는 계속해서 통신을 할 수 있는 것이다. 그리고 양방향 모두 가능하다. 데이터의 확인 절차도 거치게 된다. 만약 전화가 잘 들리지 않는다면 상대방은 '뭐라고요?'라고 할 것이다. TCP 프로토콜도 자료를 받지 못했다면 다시 요청하는 메커니즘을 가지고 있다.

    (2) UDP 통신의 개념
      : UDP(User Datagram Protocol) 통신은 편지에 비유할 수 있다.

    편지를 쓸 때 편지지에 데이터를 기록하고 편지 봉투에 상대방의 주소와 자신의 주소를 표시한 후 그냥 보내 버립니다. 편지가 도착했는지 않았는지 알 수 없다. 이러한 원리는 UDP에서 그대로 적용된다.

    먼저 데이터를 생성한 후 상대방의 주소와 자신의 주소를 기록하고 보내버리면, 그 데이터를 받았는지 확인할 방법은 없다. 단지 보냈다는 사실만 존재할 뿐이다. UDP 통신 자체는 상대방과 연결되어 있는 개념이 아니다 .자신의 로컬 머신에서 소켓을 개설하고 데이터를 랜카드에 실어 버리는 개념이다. 때문에 편지를 우체통에 넣어버리는 개념과 흡사한 것이다.

    편지를 받는 사람 입장에서 생각해 보자. 편지가 왔는지 안왔는지 편지함을 열어보기 전에는 알 수 없다. 이것과 마찬가지로 상대방이 UDP를 통해서 데이터를 보냈다 하더라도 UDP 소켓을 통해서 자신의 포트를 열어보기 정네는 데이터가 왔는지 오지 않았는지 알 수 없다. 즉 자신의 로컬 머신에 소켓을 개설하고 데이터를 들어왔는지 오지 않았는지를 확인하는 메커니즘이 필요하다. 이것은 편지가 우편함에 있는지 없는지를 확인하는 것에 비유할 수 있다.

    (3) 비교 분석

      :  TCP와 UDP 프로토콜의 통신 메카니즘의 차이는 일반적인 생호라에서 쉽게 찾아볼 수 있습니다. TCP 통신은 데이터를 주고 받을 때 데이터가 도착했는지 하지 않았는지 내부적으로 확인하게 됩니다. 만약 하지 않았다면 재요청을 하는 메카니즘을 가지고 있습니다. 이러한 확인 절차로 인해 속도면에서 느립니다 .하지만 UDP는 이러한 확인 절차를 거치지 않고 계속적으로 데이터를 보내기만 하고 받기만 하기 때문에 휠씬 빠른 속도로 처리될 수 있습니다.

    속도면에서 UDP가 빠르지만 UDP는 데이터가 정확하게 도착했는지 하지 않았는지 알 수 없는 비신뢰성 프로토콜입니다. 이에 반해 TCP는 이를 보장하는 신뢰성 프로토콜입니다.

    쉽게 이야기 하자면 TCP 는 전화와 비슷한 방식을 제공한다. 서로 연결된 상태에서만 정보를 교환 할 수 있다. UDP는 편지나 방송과 비슷하다. 발송된 편지는 수신자가 받았는지 안받았는지 알 수 없다. 전달하게 되면 그만인 것이다.

    방송과 같은 경우도 비슷하다. KBS나 MBC에서 브로드캐스팅된 정보를 각각의 가정에서 받아 TV 화면으로 보지만 우리는 그것을 잘 받았다고 MBC나 KBS에 응답하거나, 잘못된 수식된 화면에 대해 재요청하거나 하지 않습니다.

    용어를 좀 정리하면 전화가 유니캐스트,
    방송이 브로드 캐스팅,
    멀티캐스트는 브로드캐스트와 비슷하지만 전체 중 선택된 그룹만 보내는 것을 말한다.


    --------------------------------------------------------------------------------------------------------------------------]
    TCP 통신
    TCP(Transmission Control Protocol)는 인터넷에서 가장 흔하게 그리고 많이 쓰이는 프로토콜 방식이다. 그 이유는 TCP통신은 error correction이라는게 존재하는데 말 그대로 에러를 다시 잡아주는 것이다. 서버에서 클라이언트에게 어떤 정보를 보냈다고 하자! 그러면 클라이언트는 서버가 보낸 정보를 제대로 받았는지, 확인해주는 메세지를 다시 서버에게 돌려주고, 클라이언트가 제대로 받지 못했을 경우엔 resend를 서버에 요청 할 수 있다. 그러면 loss된 데이터를 다시 클라이언트에게 보낼 수 있는 것이다. 이런 방법들을 flow control이라고 하며, 오리지널 데이터를 로스 하지 않고 받을 수 있게 한다. 즉, guaranteed delivery!

    - UDP 통신
    UDP(User Datagram Protocol) 은 인터넷에서 또 많이 쓰이는 프로토콜인데 그 사용처는 tcp 통신과는 다르다. tcp통신과의 가장 큰 차이는 단방향 통신이라는것! 서버가 클라이언트에게 혹은 클라이언트가 서버에게! error correction이 없고, 무조건 보내는 쪽에선 던지기만 하고 받는 쪽에선 받기만 한다. 그러다가 데이터 로스가 중간에서 발생하면 어쩌냐? 무시한다. 그냥 던지고 받는거다 ! 이렇게 되면 장점은 TCP통신 보다는 훨씬 빠른 전송을 보여주게 된다.

    두 통신방법은 사용되는 곳이 다르다. 웹페이지 전송이다. 어떤 데이터 베이스를 전송할때는 반드시 TCP통신이 사용되어야 한다. 웹페이지가 전송오류로 얼빵한 화면이 떠져 있다면 사용자는 얼마나 황당하겠는가... 데이터 베이스는 물론이고
    UDP통신은 비디오 오디오 신호 전송에 사용된다. 빠른 프레임으로 돌아가는 비디오 스트리밍 프로그램에 한두 프레임 로스가 생겼다고 resend를 재요청하고, 데이터 로스를 일일이 확인해서는 버퍼링 때문에 오히려 속터질것이다.  몇 프레임 정도 놓쳐도 오히려 상관없고 놓친 프레임은 과감하게 버리는 방식. 큰 파일을 스트리밍으로 내려 받을 때 적합하다. 인터넷 스트리밍 영상이나 음향들이 퀄리티가 오프라인으로 받아놓고 보는것 보다 좋지 않은 이유도 이것이다.

    --------------------------------------------------------------------------------------------------------------------------]

    CP/IP

    2014년 4월 22일 화요일

    TCP와 UDP 개요와 비교

    TCP/IP 전송 계층의 두 프로토콜 요구사항

    • 전송 제어 프로토콜(TCP)
      • TCP는 기능이 풍부하고, 연결형이며, 신뢰할 수 있는 TCP/IP 애플리케이션을 위한 전송 계층 프로토콜이다.
      • TCP는 여러 소프트웨어 애플리케이션이 동시에 단일 IP 주소를 사용할 수 있도록 하는 전송 계층 주소지정 방법을 제공하며 한 쌍의 장비가 가상 연결을 수립하고 양방향으로 데이터를 전달할 수 있도록 한다.
      • 전송은 승인받지 않은 패킷을 탐지하여 자동으로 재전송하는 특수한 슬라이딩 윈도우(sliding window) 시스템으로 관리된다.
      • 그리고 TCP는 장비간의 흐름 관리, 기타 특수 상황을 처리하기 위한 추가 기능도 제공한다.
    • 사용자 데이터그램 프로토콜(UDP)
      • UDP는 매우 단순한 전송 프로토콜로 TCP와 유사한 전송 계층 주소지정 방법을 제공하지만, 다른 기능은 거의 제공하지 않는다.
      • UDP는 애플리케이션이 IP에 접근할 수 있도록 하는 래퍼 프로토콜에 가깝다.
      • UDP에서는 연결이 수립되지 않고, 전송도 신뢰할 수 없으며, 데이터가 손실될 수 있다.

    TCP와 UDP 애플리케이션

    • TCP 애플리케이션
      • 대부분의 애플리케이션은 TCP가 제공하는 신뢰성과 여러 서비스를 필요로 하며, TCP로 인해 생기는 약간의 부하로 인한 성능 저하에 신경 쓰지 않는다.
      • 하이퍼텍스트 전송 프로토콜(HTTP), 파일 전송 프로토콜(FTP), 단순 메일 전송 프로토콜(SMTP) 등이 있다.
    • UDP 애플리케이션
      • 데이터 일부가 손실되는 것이 그리 중요치 않은 애플리케이션(ex: 비디오나 멀티미디어 스트리밍)에 적합하다.

    UDP와 TCP 비교 요약
    특성/설명UDPTCP
    일반 설명단순하고, 빠르며, 애플리케이션이 네트워크 계층에 접근할 수 있도록 하는 인터페이스만 제공할 뿐 다른 것은 거의 하지 않음애플리케이션이 네트워크 계층 문제를 걱정하지 않고 데이터를 안정적으로 송신할 수 있도록 하는, 풍부한 기능의 프로토콜
    프로토콜 연결 수립비연결형. 연결 수립이 없이 데이터를 송신함연결형. 전송 전에 연결을 먼저 맺어야 한다.
    애플리케이션의 데이터 입력 인터페이스메시지 기반임. 애플리케이션은 데이터를 별도의 패키지로 송신한다.스티림 기반임. 애플리케이션은 특정한 구조 없이 데이터를 송신한다.
    신뢰성과 승인신뢰성이 없음. 승인이 없는 최선 노력 전송 방식메시지 전송을 신뢰할 수 있음. 모든 데이터에 대한 승인이 있음
    재전송수행하지 않음. 애플리케이션은 손실 데이터를 탐지하고 필요할 경우 재전송해야 함모든 데이터 전송을 관리하며, 손실된 데이터는 자동으로 재전송함
    데이터 흐름 관리 기능없음슬라이딩 윈도우를 이용한 흐름 제어를 함. 윈도우 크기를 적절히 조정하고, 혼잡 회피 알고리즘을 사용함
    부하매우 낮음낮지만 UDP 보다는 높음
    전송 속도매우 빠름빠르지만 UDP 만큼은 아님
    적합한 데이터 양소형에서 중형 데이터(최대 수백 바이트)소형에서 초대형 데이터까지(최대 수 기가 바이트)
    프로토콜을 사용하는 애플리케이션의 유형데이터의 완전성보다 전달 속도가 중요하고, 소량의 데이터를 송신하고, 멀티캐스트/브로트캐스트를 사용하는 애플리케이션신뢰할 수 있는 방법으로 데이터를 송신해야 하는 대부분의 프로토콜과 애플리케이션. 대부분의 파일/메시지 전송 프로토콜을 포함함
    유명 애플리케이션과 프로토콜멀티미디어 애플리케이션, DNS, BOOTP, DHCP, TFTP, SNMP, RIP, NFS(초기버전)FTP, Telnet, SMTP, DNS, HTTP, POP, NNTP, IMAP, BGP, IRC, NFS(나중버전)