프로그래밍언어

[프로그래밍언어] Data Types_Union Types, Pointer and Reference Types, Type Checking, Strong Typing

Union Types

Union은 실행시간의 다른 시간들동안 다른 타입의 값들을 저장할 수 있도록 하는 타입입니다.

단점은 type checking이 dynamic해야한다는 것입니다. 

union Type{
int i;
short int s[2];
char c[4];
};

Free Union은 type checking을 제공하지 않아 unsafe합니다.

type checking을 하는 union은 discriminant라는 type 지시자를 가지고있습니다.

Java와 C#은 Union을 제공하지 않습니다. 

 

Pointer and Reference Types

포인터타입 변수는 메모리주소를 가지고 NULL(nil)이라는 특별한 값을 가집니다. 

ptr=NULL; 하면 메모리가 해제됩니다. 

indirect addressing과 dynamic memory를 제공합니다. 

pointer는 dynamically하게 생성되는 공간(heap)을 접근합니다.

 

Design Issues for Pointers

(중요!!!!) 언어가 pointer type, reference type, 아니면 둘다,,,,무엇을 지원해야하나요?

 

포인터는 assignment(할당)과 dereferencing(역참조) 연산을 하는 아이입니다.

 

Dangling Pointers

포인터로 발생하는 문제 중 하나입니다.

이미 메모리해제된 heap-dynamic variable을 가리키는 포인터를 dangling pointer라고 합니다. 

같은 heap에 포인터p1과 p2가 가리키고 있다가

*p1=NULL을 한 경우 deallocation(회수)작업이 일어납니다.

그러면 Heap은 deallocated되어 사라집니다.

그러면 포인터 p2는 dangling pointer가 된 것입니다. 

(참고) C++에서 delete[]ptr;

C++에서 delete[]ptr; 는 NULL로 메모리해제한 것이 아니라 그냥 OS에게 ptr을 넘겨준 것입니다. 그래서 os는 해당메모리를 다른 응용프로그램에서 다시 할당할 수 있습니다. 

delete연산자는 실제로 아무것도 삭제하지 않고 포인터변수는 여전히 이전과 동일한 범위를 가지며 다른 변수와 마찬가지로 새 값을 할당 받을 수 있습니다. 

 

Lost heap-dynamic variable 

이것 또한 포인터로 발생하는 문제 중 하나입니다. 

할당된 heap-dynamic variable이 더 이상 접근 불가능해져(분실되어) 한마디로 garbage 쓰레기가 된 것입니다. (쓰레기값 계속 들어갈 수 있음) 

이는 memory leakage문제도 발생할 수 있습니다. 

 

void*

(void*)는 어떠한 타입도 가리킬 수 있고 type checked될 수 있습니다.(어떤 자료형의 주소도 저장가능)

de-referenced역참조는 불가능합니다. (* 연산자 사용 불가) 

값의 변경, 참조, 포인터 연산 불가능. 

void main(){
void *vp;
int n=10;
vp=&n;
*vp=20;//cannot be dereferenced
vp++;//compile error
}

void pointer가 가지고 있는 주소의 메모리에 접근하려면 해당 주소를 형변환(type conversion) 후 접근 가능합니다. 

즉, void형 포인터 변수는 일단 주소값에만 의미를 두고, 포인터의 형은 나중에 결정. 

메모리의 동적 할당과 매우 밀접하다.(generic pointer) 

void main(){
void *vp;
int *ptr;
char c = 'A';
int num=10;

vp=&c;
printf("%c\n",*(char*)vp);//타입캐스팅

vp=#
ptr=(int*)vp;//타입캐스팅
printf("%d\n",*ptr);
}

Reference Types 

C++이 사용하는 포인터 타입으로 formal parameter로 주로 사용됩니다. 

pass-by-reference와 pass-by-value로 모두 쓰일 수 있습니다. 

아래 포스트에 formal parameter, pass-by-reference, pass-by-value에 관한 내용이 담겨 있습니다. 

https://hidemasa.tistory.com/32 

 

[프로그래밍언어]Subprograms

추상화에는 두 가지 종류가 있습니다. Process abstraction Data abstraction(이는 여기서는 다루지 않을 내용입니다.) 우리가 메인함수에서 프로세스를 구성해서 f1(a,b)라는 subprogram을 호출했을 때 f1()이라

hidemasa.tistory.com

포인터는 메모리의 주소를 가리키고 

레퍼런스는 메모리의 객체나 값을 가리킵니다. (Java는 포인터사용x)

 

레퍼런스는 pass-by-reference로 subprogram의 parameter입니다.

 

 

Pointer vs Reference(중요!!!)

공통점: 다른 객체(또는 변수)를 간접적으로 참조

차이점:

-Null Pointer(o), Null Reference(x) 

포인터는 자신이 참조하는 대상을 원하는 아무 때나 참조할 수 있지만, 레퍼런스는 자신이 선언되는 순간에 참조하려는 대상을 알고있어야함. 

int *pnum=NULL; //PASS
int &rnum=NULL; //error

int num=100;
int &rnum=num; //PASS (레퍼런스는 선언시 반드시 초기화) 

레퍼런스는 그 대상이 언제나 존재하기 때문에 유효성검사를 할 필요가 없지만, 

포인터는 그 대상이 존재하지 않을 수 있기 때문에 사용전에 언제나 유효성 검사가 필요합니다.

string name("whitesnake");
string *ps= &name; //유효성검사: ps존재유무 확인후 사용
if(ps)
	cout<<ps;

초기화할때, 레퍼런스는 객체(또는 변수)를 직접 (값) 입력, 포인터는 객체(또는 변수)의 주솟값을 입력

//reference initialization
string name("whitegold");
string &ref=name; //name(대상)을 직접할당, ref 자신이 name이 되는 것

//pointer initialization
string name("whitegold");
string *ptr=&name; //name의 주솟값을 할당 

레퍼런스는 한 번 가리킨 대상의 변경(x), 포인터는 자신이 가리킨 대상을 언제든지 변경(ㅇ)

 

차이점: Class member에 접근할때, 레퍼런스는 . 를 사용하고 포인터는 ->를 사용

접근비용의 차이: 포인터를 위한 메모리공간 필요, 레퍼런스는 필요없음.

 

 

Heap Management(중요)

복잡한 run-time process 입니다. single-size cells와 variable-size cells가 있는 variable-size는 과정이 복잡해서 OS가 하므로 알 필요 없고 single-size cells는 모든 heap storage가 할당해제가 single size단위로 된다는 뜻입니다.

 

garbage 회수하는 방식에는 두 가지가 있습니다

Reference counters (점진적인 방법) 

ptr 개수를 세서 ptr되지 않는거(가리키는게없는것)은 회수합니다. 

처음에 자기를 가리키는 포인터수를 기억후 counter로 포인터가변경될때 참조횟수를 재계산합니다.

재계산시 참조횟수가 0이 되면 수거(deallocation) . 계속 연속적으로 수거

(Cycle이 있다면 수거되지 않을 수 있음_cycle이 생기지않도록 주의해야함)

장점: reference counter 액션이 번갈아 실행되므로 마치 데이터들이 동시 보내는 것처럼 delay없이 섞어서 보내집니다. 

 

Mark-Sweep

포인터로 도달가능한 셀을 모두 표시(mark)해둔 후,

표시되지 않은 셀을 모두 수거(sweep) 

한번에 확 해제하므로 overhead를 조심해야합니다.

이를 방지위해 incremental mark-sweep이 있습니다. (주기적으로 자주하기) 

 

 

Type Checking(시험!!!중요!!!)

타입체킹은 피연산자들이 다 compatible(상호호환)한 타입인지 확인하는 것입니다. 

a+b;에서 a는 int이고 b는 char이라면 type checking에서 type error로 체킹될 것입니다.

 

모든 타입 바인딩이 static이라면 type checking은 static이라 가장 좋다.

하지만 타입 바인딩이 dynamic하다면, type checking도 dynamic 해야하서 어렵다. 

 

Strong Typing 

그래서 프로그래밍 언어는 strongly typed해서 compile time에 항상 걸러지게 할 수 있다.

장점은 type errors들을 모두 걸러준다는 것입니다. 

모든 피연산자들의 타입이 컴파일시간(가급적)이나 실행시간에 결정됩니다.

union같은 변수는 실행시간에 검출해야합니다. 

C와 C++는 strongly typed 언어가 아닙니다. (대표적: union)

Java, C#은 strongly typed 언어입니다. 

 

Coercion rules(강제형변환)은 strong typing을 저해하는 요소입니다.

 

Name Type Equivalence(개념체크!!!중요!!!)

두 개의 변수가 동등한 타입을 갖는다는 의미입니다.

int x, y; 이나 int x; int y; 

 

Strucure Type Equivalence 

만약 같은 structure을 가진 타입이라면 두 개의 변수가 동등한 타입을 가졌다는 의미

더 유연하지만, implement가 어렵다. 고려해야할것이 많다. 

 

 

C: array, typedef. - structure type equivalence

   Struct, union, enum -name type equivalence

C++: name type equivalence