형은 데이터에 붙은 추가데이터다.

컴퓨터는 데이터를 on/off, 1과 0의 집합으로 표현한다.

같은 비트열 형식이지만 컴퓨터가 어떻게 처리할 지를 CPU에 알리는 것이 형의 시작이다.



데이터를 지금의 비트열로 표현하기 까지는 많은 과정이 있었다.

적은 수의 on과 off를 이용해서 많은 데이터를 표현할 수 있어야 한다.


그래서 자릿수나 8진수, 16진수가 나온것이다.

 

1983년에 닌텐도가 출시한 패밀리 컴퓨터는 8bit를 사용했고, 현재는 보통 64bit를 이용해 데이터를 표현한다.


파이썬 3.0 에서는 8비트, 1


즉, 형이 생기게 된 근본적인 이유는 컴퓨터의 연산처리와 관계가 있는데 변수형 선언을 함으로써 정수는 CPU는 어떤 계산을 할 지 아는 것이다.

이렇게 알리는게 중요한 이유는 예를들어 부동소수점과 고정소수점의 연산 방법에는 차이가 있기 때문이다. 




그렇다면 형은 어떻게 발전하였을까?


1. 이런 기본형 외에도 개발의 편의를 위해서 사용자가 임의로 형을 정의할 수 있게 되었다.

C언어의 구조체가 대표적인 예이다. 

실제로 리눅스는 OOP의 개념을 굉장히 추구하고 반영하고 있는데, C로 작성되었기 때문에 OOP를 클래스가 아닌 구조체 단위로 구현한다.


C++ 설계자인 바얀교수는 사용자가 정의하는 형이야 말로 프로그램 구축에 기본요소라 생각하여 개념을 도입했고, 클래스라고 이름을 붙였다.


2. 형은 통해서 접근레벨을 사용하여 public, private같은 접근권한을 설정 할 수 있게 되었다.

구조체나 클래스를 구성하는 형을 최소한만 공개하여 코드를 보호한다는 의미이다. 형이 맞는지 틀린지는 컴파일단계에서 컴파일러가 해준다. 그래서 이런 사양을 형으로 표현하게되면 우리는 개발을 할 때 컴파일러에게 유용한 도움을 받을 수 있게 되는 것이다.


3. 이런 개념은 인터페이스로까지 발전되었다. 인터페이스 처럼 추상적인 개념을 개발할 때 컴파일러가 오류를 검출해 주기때문에, 우리는 잘못된 코드를 작성할 걱정과 수고를 덜 수 있게되었다.





형은 다시 재정의 할 수 있다. 다시 말하면 기존의 형을 구성 요소의 일부분을 바꾸어 다시 재사용 할 수 있다는 말이다.

C++의 template, Java의 generics,  Haskell의 형 생성자 등이 해당된다.









출처. 코딩을 지탱하는 기술

컴퓨터 이전의 부호화


모스부호 morse code,

1836년에 발명되어 1865년 International TelegraphyCongress에 의해 국제표준화 구격이 된 부호화 방법이다.

무선기에 연결된 스위치를 통해 전파를  On/Off로 입력하여 통신에 이용한다.


보코드

모스부호는 사람이 직접 수고를 하였다. 통신 분야가 발전하면서 보다 빠른 송신방법이 요구되었다.


텔레타이프 단말기가 등장하였는데, 타자기가 전화선에 연결되어있는 모양으로 키보드를 눌러서 문자를 입력하고 수신자는 수신한 문자를 프린터로 출력할 수 있었다.


이후 보다 많은 양의 정보를 교환하려는 필요가 생기고 펀치 테이프와 가독기를 연결하여 사용하게 되었다.


사람이 송신하고자하는 내용을 미리 펀치테이프에 기술하여 기계가 읽어들여 송신할 수 있는 구조이다.


이 텔레타이프 단말기가 연결된 국제적 통신기가 텔렉스다.

1931년에 최초로 서비스가 시작되었고 여기서 사용한 방식이 baudot code이다.


한 문자당 5bit로 on/off의 조합을 가진다. 즉 SOS는 총 15개의 bit로 표현하였다. 또 공백, 개행 등 제어 코드를 문제 세트에 추가하였다. 



EDSAC 문자코드

텔렉스로부터 약 20년 후 199년에 만들어진 EDSAC.


한 문자에 5bit를 사용하고 천공테이프(종이테이프에 구멍을 뚫어서)를 이용했다.


ASCII와 EBCDIC

EDSAC 이후에 10년간 다양한 컴퓨터가 만들어졌고, 문자 부호화 방식도 제각각이었다.

제각각인 문자 부호화 방법을 표준화하기위해 American Standard Code for Information interchange의 약자로 ASCII가 1963년에 제정의 되었다.


한 문자당 7비트를 사용하여 127종류의 문자를 표현했고 여기부터 소문자도 포함


하지만 1963년 이당시에 컴퓨터 시장을 장악하고 있던 IBM이 ASCII와 다른 EBCDID방식을 공개하였다.  결국 통일이 안되었고 심지어 EBCDID자체에도 여러 버그가 존재했다.

다른 부화화방식(문제체계와)과 호환에 문제가 있었다.


계속 불편..

결국 1984년 전 세계의 문자 부호화 방법을 통일하자는 움직임이 시작됐고 1984년 ISO가 universal Character Set(UCS) 표준화를 시작.

Xerox도 이와 별도로 1987년에 작업을 시작해서 1989년 최초 시안의 Unicode Draft1을 공개. 

결과적으로는 Unicode에 ISO의  USC가 일체화 되는 형태로 1993년에 국제화 표준이 됨 


이래서 전세계 문자를 포함한 문자집합 Unicode가 탄생





현재 프로그램 언어가 표현하는 문자열은 두가지가 있다.

C언어의 문자열은 자신의 길이를 알지 못하고, Pascal, Java, Ruby, Python은 문자열의 길이를 알고있다.




1. C 

하나의 문자를 8비트로 정의한다.

C언어의 문자열은 문자열이 시작되는 메모리상의 위치를 가지고있고 길이 정보를 가지고 있지 않아서 해당 위치에서 어디까지가 문자열인지 알수가 없다.


문자열의 끝을 표시하기 위해서 C언어는 문자열의 끝에 NUL 문자를 삽입한다. 

NUL은 0에 대응하는 문자이며 코드상에서는 \0으로 표현한다.


* ASCII에서 null character를 NUL이라고 쓰기로 정의한다.

C언어는 pointer를 다루는데 NULL pointer라는 개념이 있어서 문자열에 대한 NULL은 ASCII에서 표현하는 NUL이라고 기재하도록 한다.


8비트로 표현할 수 있기때문에 0~255로 표현할 수 있는 ASCII, 혹은 EBCDID의 문자



2. pascal 도 한 문자당 8비트로 표현한다.

하지만 pascal의 문자열은 문자열 앞부분에 길이정보를 가지고 있다. 대부분의 언어들은 문자열을 표현할 때 이와같이 표현되고있다.


3. java

자바에서는 한 문자는 16비트로 표시된다.

16비트로 표현되므로 0~65,535로 표혛날 수 있는 Unicode의 한 문자이다.



python은 자바와 같이 16비트의 unicode문자열과 pascal과 같은 8비트 문자열을 모두 지원한다.

python2 에서는 소스코드에 '아'라고 하면, UTF-8인 경우 3개의 바이트가 들어간 ['0xe3'. '0x81', '0x82']로 되고

u"아"라고하면 유니코드로 ['0x3042']가 된다.


파이썬2에서는 바이트열이 ASCII범위에 포함되면 ASCII로 간주되고 자동으로 UNIcode로 변환하는 설계로 되어있었다.

오로지 Unicode문자열에 바이트열을 결합하기 위해선 ASCII로만 이루어져있어야 가능했다.


하지만 이는 ASCII를 사용하지 않는 나라에서는 문제가 되었다. 

그래서 파이썬 3에서는 이전버전과의 호환성을 아예 버리더라도 유니코드가 기본이 되도록 하였다. 즉 '아'라고 하면 유니코드 문자열이 되고,

b'아'라고하면 8비트 문자열이 되도록 변경하여 유니코드를 손쉽게 사용할 수 있도록 하였다.  

그리고 문자열 형식의 형변환 시 명시적으로 하도록 했다. 


즉 유니코드 문자열에 바이트 문자열을 붙일 시에는 명시적인 형변환으 통해서 바이트 문자열을 유니코드로 형변환 한 후 문자열을 결합하여야 한다.







출처. 코딩을 지탱하는 기술

전역스코프 동적스코프 정적스코프


일반적으로 스코프를 사용하여 이름의 유효범위를 지정 해야한다. 스코프는 어떻게 동작하는지 알아보자.



동적스코프

전역에 x라는 변수가 있다고 하자. 그리고 지역함수에도 x라는 변수가 있다고 하자.

지역함수에 들어오면 전역에 위치한 x가 어떤 값을 가지고 있더라고 지역함수 내의 x는 지역함수 내에서 만큼은 값을 보장받을 수 있다. 즉 지역함수 내에서는 갓이 유효하다.

이는 전역의 변수의 값을 다른 곳에 저장한 후 지역함수를 빠져나갈때 값을 되돌리기 때문이다. 이를 수행해 주는것이 동적스코프이다. 참고로 perl 4(1991년) 부터는 변수를 local이라는 키워드로 선언하면 이를 알아서 해준다. 



Perl


$x = "global";


sub yobu {

local $x = "yobu";

&yobareru();

}


sub yobureru {

print "$x\n";    # yobu 라고 출력됨

}


&yobu();


이 예제에서는 yobu() 함수의 지역변수 x가 sub함수 yobareru()까지 영향을 미친다.

동적 스코프는 변경값이 호출되는 곳에 파급되기 때문에 어떤 값이 될지 코드를 보지 않고서는 알 수 없다. 코드의 양이 많아지면 정말 귀찮은 일이 될것이다.


변수들의 데이터를 다른 곳에 저장하는 대신 대웅표라는 것을 만들어 관리한다. 

동적 스코프와 전역 스코프는 이 대응표를 프로그램 전체에 결쳐서 몇 개의 함수가 공유하고 있다. 


함수에 들어가면 새로운 대응표가 만들어진다

해당 함수 안에서의 내용은 대응표에 기록되지고 사용된다.

해당 함수를 벗어날 대 이 대응표를 제거한다.


그리고 변수를 참조할 때에는 가까운 곳에서 부터 순서대로 읽는다.
이것이 위의 예제에서 결과가 yobu인 이유이며, 만약 지역에 변수가 없다면 전역변수의 값이 출력될 것이라고 짐작할 수 있겠다.

 여러 함수에서 대응표를 공유하기때문에 문제가 발생한다면 함수별로 대응표를 나눠볼 수 있을 것이다. 이것이 정적스코프가 동작하는 개념이다.


함수에 들어가면 해당 함수 전용의 새로운 대응표를 준비한다.

함수내에서의 내용은 해당 대응표에 기록되고 사용된다

함수를 빠져나갈때 해당 대응표를 제거한다.


정적스코프라고 가정하에 다시 예제를 보자.


Perl


$x = "global";


sub yobu {

my $x = "yobu";

&yobareru();

}


sub yobureru {

print "$x\n";    # global 라고 출력됨

}


&yobu();



yobareru에서 x를 참고할 때 해당 함수의 대응표에는 x가 없다. 그러므로 yobu함수의 대응표가 아닌 바로 전역을 읽는다. 

우리는 이 방식이 일반적인 것이라고 생각한다. 그렇다. 현재 많은 언어가 정적 스코프를 도입하고 있기 때문이다. 


JavaScript에서도 var를 붙이지 않으면 전역스코프이고 var를 붙이면 정적스코프이다. 

몇몇 언어들은 스코프방식이 변하기도 했다.


Python은 처음부터 정적 스코프였다. 

Python2.0 에는 스코프가 3가지가 있다.


지역, 전역, 빌트인

빌트인은 프로그램의 어디에서든 참조할 수 있는 스코프이며 여기에는 문자열화 함수stir이나 Runtime(실행 시)  Error등이 있다.

이는 언어에 기본 탑재되어 있는 함수나 예외이므로 빌트인이라고 한다. 



python2.0에서 전역 스코프는 파일 단위로 존재한다. 따라서 파일 스코프라도고 한다. 


 


python은 대입과 함께 변수를 만드는 언어이다. 함수안에서 대입을 하면 아무것도 선언하지 않더라도 지역변수가 된다.

이는 두가지 문제를 만들 수 있다.



이제 파이썬에서 발생할 수 있는 스코프 문제를 살펴보자


첫번째, 





실제로 2.0 버전에서는 함수 bar()의 지역 스코프에서 이름 x를 발견하지 못하면 전역스코프를 보러 가는 설계로 되어있다(그림7.9의 1번). 

결국 수정할 필요가 있는 문제점이라고 인식되어 2001년에 공개된 Python2.1에서는 그림7.9의 1번처럼 동작하도록 수정되었다.




두번째, 


대입과 함께 변수를 만들기 때문에, 함수에 지역변수가 없으면 바로 지역스코프 변수로 생성한다.

처음에는 JavaScript처럼 var변수를 이용해서 해결하고자 했지만, 과거 코드와 호환성이 없어서 채택되지 않았고


2006년 3.0버전에서 nonlocal이라는 키워드로 선언하여 사용하도록 채택되었다.




이런 스코프 개념은 언어마나 한가지로 정의되지는 않는다.


자바의 경우 정적스코프의 언어이지만 java의 클래스는 소스코드 어디서든 참조할 수 있다. 

즉 클래스는 전역 스코프를 사용하는 것이다. 클래스는 이름이 계층적으로 이루어져있고, 임포트하지 않으면 사용할 수 없어서 전역변수가 가지고 있던 충돌 문제를 피한다. 

그리고 잘 알고있는 static 변수도 전역스코프의 변수이므로 소스코드 어디든지 바꿀 수 있다. 

하지만 static변수를 사용할 때 주의를 해야하는 이유는 남용하게되면 이해하기 어려운 코드가 되기 때문이다.






출처. 코딩을 지탱하는 기술

'Development > Etc.' 카테고리의 다른 글

type(형)  (0) 2016.02.06
언어별로 문자열 처리  (0) 2016.02.06
상속이 is-a 관계여야 하는이유와 delegation  (0) 2016.02.06
언어별 클래스의 의미  (0) 2016.02.06
이벤트기반과 메세지기반 아키텍처의 차이  (0) 2016.02.06

+ Recent posts