⑴ DeadLock과 그 해결책멀티프로그래밍 환경에서의 몇 가지 프로세스는 유한의 리소스를 차지하려고 싸웁니다. 한개의 프로세스가 리소스를 요구했을 때 만일 그 리소스가 현재 더 이상 제공이 불가능할 때는(다른 프로세스가 이미 그 리소스를 가져가서 쓰고 있는 경우) 자신을 대기상태로 전환시킨 뒤 해당 리소스가 제공이 가능할 때 까지 그 상태를 유지합니다. 이때, 대기상태에 돌입한 프로세스가 영영 자신의 상태를 전환시키지 못하는 경우가 발생하는데, 그 이유는 기다리고 있는 리소스들을 쥐고 있는 프로세스들 역시 같은 이유로 대기상태에 빠져있기 때문이죠. 우리는 현재 이렇게 영원하게 대기상태로 빠져버린 일련의 프로세스들이 처해있는 상황을 바로 데드락이라고 일컫는 것입니다.데드락 해법은 근래에 들어서야 조금씩 추가되고 있는 경향인 듯 합니다. 이는 현대의 오에스에서는 예전과는 비교할 수 없을 만큼 다양한 프로세스들 및 다양한 리소스들이 난무하고 있고, 한번 생성되면 예전보다 더욱 오래 작업을 하는(long-live) 파일등이 데이터베이스 등과 함께 현대 기술의 총아로 떠오르기 때문인 듯 합니다.먼저 여기서 말하는 리소스가 무엇인지 알아봅니다. 리소스를 몇가지 범주로 나누어 보면 크게 메모리 공간, 씨피유 싸이클, I/O장치 등으로 나눌 수 있겠죠. 만일 2개의 씨피유가 달린 시스템이라면 그 시스템에서 '씨피유 타입의 리소스는 두개의 인스턴스(instance)를 가지고 있다'라고 말하게 됩니다. 리소스를 정의할 때 한가지 주의할 사항이 있는데, 프린터가 2대 있다고 합시다. 만일 프린팅 프로세스가 프린터 리소스의 인스탄스를 요구할 때, 그 프린터가 만일 서로 옆에 놓여있다면야 둘 중 하나의 인스탄스를 넘겨줄테니 2개를 같은 리소스 타입의 인스턴스로 설정해도 무방하지만, 만일 한 개는 1층, 또 한 개는 10층에 놓여있다면 이때는 문제가 달라집니다. 즉, 다른 종류 타입의 인스탄스가 1개씩 있다고 설정을 하지 않는다면 유저는 프린트 명령을 보낸 뒤 1층에서 10층까지 헛수고를 하게 됩니다. 언제 어느 프린터의 리소스 인스턴트를 사용할지는 그때의 상황에 따라 달라지니까요.리소스를 프로세스가 활용하는 데에는 다음의 3단계 과정을 거치게 됩니다. 1. 요구(Request) 2. 사용(Use) 3. 해제(Release) 이때 리소스의 요구 및 해제는 세마포어의 wait및 signal로 수행하게 됩니다. 또한 오에스는 리소스의 사용 가능 및 불가능에 대한 기록을 시스템 테이블에 기록하게 되지요.먼저 리소스가 일어나기 위한 4가지 필요조건이 있습니다. 필요조건이라는 뜻은 여기서 '데드락이 일어나서 한번 살펴보니 그 상황이 반드시 4가지 조건을 모두 따르더라' 입니다. '4가지 조건 모두에 어떤 상황이 해당된다고 해서 반드시 데드락이 일어날것이다'는 아니죠.1. 상호배타성(뮤텍스:Mutual Exclusion): 존재하는 리소스!중 최소한 한개는 절대 공유가 불가능한 모드에 놓여있는 경우입니다. 2. 쥐고기다리기(Hold&Wait): 존재하는 프로세스!중 최소한 한 개는 최소한 한 개의 리소스를 꼬옥 쥐고서 더 필요한 리소스를 기다리고 있는 경우입니다.(물론 더 필요한 리소스는 현재 다른 프로세스가 쥐고 있죠) 3. 선점불가(No Preemption): 리소스의 선점이 허용되지 않을 경우입니다. 즉, 한 개의 프로세스가 일단 리소스를 쥐게 되면 자신의 임무를 완수한 뒤 자진 해제하지 않는 이상 그 누구도 그의 리소스를 빼앗을 수 없는 경우입니다. 4. 원형순환기다림(Circular Waiting): 기다리고 있는 프로세스의 집합 {P0, P1,..., Pn}이 반드시 존재하되, 이때 P0은 P1이 쥐고 있는 리소스를 기다리고, P1는 P2의,,,마지막으로 Pn은 P0의 가 쥐고 있는 리소스를 기다리는 경우입니다.데드락을 처리하는 방법을 논해보도록 합시다. 방법은 아래와 같이 크게 3가지가 있습니다.1. 프로토콜(protocol:규약)을 이용하여 애초에 데드락이 발생하는 것을 미연에 방지하자. 2. 일단 시스템으로 하여금 데드락에 들어가는 것을 허용하되, 스스로 회복하도록 만들자. 3. 데드락문제 자체를 무시해 버리자. 그리고 데드락이 안 일어난 척 하자.먼저 1번을 구현하는 방법은 2가지로 다시 나뉩니다. 데드락방지(deadlock prevention)와 데드락피하기(deadlock aviodance)이지요. 이 둘의 뜻이 비슷한게 어째 헷갈리게 보이지만, 둘은 명확한 차이를 가지고 있습니다. 먼저 prevention은 위에서 기술된 4가지 조건 중 하나라도 만족이 안되면 결코 데드락은 발생치 않는다는 확신 하에 출발을 하죠. 그래서 리소스 할당 시 첫 단계인 프로세스의 리소스 요구에 응하기 전에 4가지 조건을 피하도록 몇 가지 제한을 가하게 됩니다. 이와 별개로 avoidance는 프로세스들이 오에스에게 먼저 리소스의 사용계획에 대한 추가적인 정보를 귀뜸해주게 됨으로서 데드락을 방지하는데, 앞으로 등장할 안전상태(Safe State)를 뱅커스알고리즘(Banker's Algorithm)을 통해 구현하는 과정에서 바로 한개의 프로세스가 최대로 몇개의 특정한 리소스를 점유할 것인가에 대한 정보가 필요하게 된답니다. 2번은 시스템으로 하여금 데드락이 발생했는지, 안했는지를 판별하고 회복하도록 만들어주는 알고리즘을 사용하게 됩니다. 이때 사용되는 알고리즘은 뱅커스알고리즘과 매우 유사하지만 약간 다릅니다. 3번처럼 무시해 버리면 시스템에서는 당연히 데드락이 발생하게 되고 시스템 리소스가 소모되면서 시스템이 점점 느려지고, 실행되지 못하는 프로세스가 발생하게 되죠. 결국은 다운이 되게 됩니다.먼저 데드락방지(deadlock prevention) 기법을 살펴봅시다. 조건1 은 뮤텍스인데, 이는 리소스의 원래 특성상 절대 공유를 할 수 없는 리소스가 존재해야만 하기에 뮤텍스를 제거하는 것은 일찌감치 포기합니다. 결론은 조건1 깰 수 없다 입니다. 조건2는 쥐고기다리기인데 이를 깨기 위하여 모든 리소스를 한꺼번에 쥐고 프로세스의 실행을 시작 하거나, 프로세스가 어떤 리소스를 요구할 시에는 자신이 절대로 다른 리소스를 쥐고 있지 못하게 하는 것이죠. 이 방법의 단점은 리소스의 활용도가 떨어짐으로써 본질적인 오에스의 목적을 위배하게 되고 특정 프로세스가 배고픔(starvation)에 시달릴 가능성에 놓인다는 것입니다. 조건3은 선점형을 적용함으로써 깰수 있는데, 이는 한 프로세스가 필요로하는 리소스를 다른 프로세스가 다른 리소스를 기다리면서 쥐고 있다면 그 리소스를 선점함으로써 빼앗아 오게 됩니다. 이는 한가지 큰 단점을 가지고 있는데, 바로 모든 리소스에 적용할 수는 없다는 사실입니다. 프린터같은 리소스에 적용을 하게 되면 여러 개의 문서가 섞여서 출력되게 되는 것입니다. 마지막으로 조건4 원형순환기다림을 깨기 위하여 모든 리소스에 번호를 부여하고, 한 프로세스가 다음 리소스를 할당할 때에는 반드시 리소스 번호가 전 리소스보다 클 때에만 할당이 가능하도록 규약을 맺게 됩니다. 그런데 효율성을 위해 리소스마다 사용되는 순서를 고려하여 번호 부여하는 작업이 매우 난해합니다.
1. 프로세스창세기 무렵의 컴퓨터들은 한번에 단 한 개의 프로그램이 실행되는 환경을 제공해주고 있었습니다. 즉, 한개의 프로그램은 시스템의 컨트롤을 완전히 독점한 체 시스템이 제공해주는 리소스에 대한 모든 권한을 쥐고 있게 되는 것이죠. 그러나, 오늘날의 컴퓨터 시스템은 여러 개의 프로그램이 메모리 안에 로딩 되고, 동시에(concurrently)실행되는 기염을 토하고 있습니다. 이러한 근대적인 환경을 제공해주기 위하여 등장하는 것이 바로 프로세스(process)라는 개념입니다.프로세스란 간단히 정의내리면 실행중인 프로그램을 의미하게 됩니다. 이것은 시분할(time-sharing)시스템의 기본 단위이기도 하지요. 결국 동시에 어떤 프로그램을 실행시킨다는 것은 시간적으로 여러 개의 프로세스를 돌아가면서 실행시키는 것으로 구현하게 되는 것입니다. 극단적으로 따지자면 결국 하나의 CPU를 가지고 있는 시스템에서는 진정한 의미의 멀티프로세싱이 불가능한 것입니다.배치시스템은 잡(jobs)단위로 실행을 하게 되지요. 이에 반해 시분할 시스템은 유저프로그램, 또는 태스크(task)단위로 실행을 하게 됩니다. 이러한 job, task 등등은 결국 비슷한 성격을 가지고 있기에 뭉뚱그려 프로세스라고 칭할 수 있습니다.프로세스를 이루고 있는 구성요소들은 실로 다양합니다. 먼저 다음번 코드를 실행시킬 코드가 들어있는 주소를 가리키고 있는 프로그램카운터(CPU 레지스터 내부에 존재), 다른 참조해야할 레지스터들의 값, 잠시 필요한 값을 저장해두는 스택, 데이터, 그리고 전역변수 등등입니다. 프로그램 그 자체와 프로세스와의 가장 중요한 차이점은 프로그램 자체는 수동적 존재임에 반해 프로세스는 위의 정보를 바탕으로 살아 움직이는 능동적 존재라는 사실입니다. 따라서 프로세스는 나름대로의 상태를 가지고 있습니다. 프로세스는 같은 프로그램에 귀속될지라도 서로 독립적으로 존재하게 되는데, 그 좋은 노트패드 같은 프로그램입니다. 노트패드의 프로그램자체는 하나만 존재하지만, 여러 개의 창을 열 때입니다.프로세스의 또 중요한 특징은, 한 개의 프로세스는 위에서 말한 각종 정보를 가지고 태어나는데, 이것이 차일드프로세스(child process)를 만들게 되면 부모 프로세스의 데이터및 스트럭쳐들이 모조리 복사되어 똑같은 프로세스가 태어나게 됩니다. 이때 생성을 가한 프로세스를 부모 프로세스(parent process), 생성된 프로세스를 자식 프로세스(child process)라고 하지요.부모 프로세스와 자식 프로세스의 관계는 참으로 엄격하면서도 유용한 구석이 있습니다. 먼저, 자식 프로세스는 글로벌이건 로컬이건 간에 가리지 않고 부모로부터 모조리 데이터를 복사해오는데, 복사된 순간부터는 각자의 길을 걷게 되지요.프로세스를 논하기 위해서는 먼저 PCB(Process Control Block)을 알아야합니다. 각각의 프로세스는 PCB로 대표되어지는데 이는 프로세스의 상태, 프로그램 카운터, CPU레지스터, CPU 스케줄링 정보, 메모리 관리 정보, 계정 정보, 그리고 I/O상태정보 등을 담고 있게 되지요. 거대한 레코드 같은 존재입니다. 그러나 하나의 프로세스를 하나의 PCB로 표현할 수 있다는 사실은 프로세스 간의 관계를 정의하고 나타내기 위해서는 매우 유용한 개념이죠.먼저 프로세스 스케줄링은 멀티프로그래밍의 목적이 언제나 활성화되어있는 프로세스들이 존재함으로써 CPU가 놀지 않고 그 활용도를 극대화 시키는 것이니 만큼, 이에 걸맞도록 설계됩니다. 스케줄링을 위해서는 언제나 큐(queue가) 필요해요. 참고로 큐(queue)란 FIFO(First In First Out)을 구현하는 데이터 스트럭쳐입니다. 먼저 온 것이 먼저 서비스를 받는다는 아이디어이지요. 한 개의 프로세스가 시스템에서 생성이 되면, 일단 잡큐(job queue)에 들어갑니다. 잡큐에 있던 것들이 메모리에 로딩되고 실행할 준비를 마치면 비로서 레디큐(ready queue)로 다시 들어가는데 레디큐는 링크드 리스트로 이루어져 있습니다. 즉, PBC로 링크드 리스트를 만드는 것이죠. 이밖에 가지고 있게 됩니다.이젠 멀티프로그래밍이 구현되는 원리를 살펴보죠. 시스템이 p0이라는 프로세스를 실행하고 있었다고 칩시다, 그런데 불현듯 p1을 위한 인터럽트나 시스템 콜이 호출되어 버리면, OS는 즉시 p0의 PCB 내부 필드의 값들을 모두 업데이트 시킨다음상태를 레디상태로 돌려버리고 레드큐에 쑤셔 넣죠. 그대신 p1의 PCB를 러닝상태로 전환 시키고 필요한 값들을 CPU의 레지스터에 주르르 펼쳐놓고 작업을 하게 됩니다. 같은 방법으로 다시 p0은 씨피유에 복귀되고 p1은 나가고,,,이런 식으로 순간순간 여러 개의 프로세스들이 자신의 상태를 바꾸어가며 질서있게 각자의 큐에서 CPU의 호출을 기다리는 것이죠.이렇게 레디큐에서 기다리는 프로세스들중 어떤것을 CPU에 불러드리는 과정을 디스패치(dispatched)되었다 라고 말하는 것이고, 도대체 어떤 프로세스를 어느때에 디스패치 시킬것인가를 결정하는 알고리즘을 프로세스 스케줄링 알고리즘이라고 합니다. 프로세스 스케줄러(구현된 스케줄링 알고리즘)는 또 크게 두가지로 나누는데 첫째는 long-term scheduler 또는 잡 스케줄러(job scheduler)라고 일컫죠. 이녀석은 생성될 프로세스중 어떤것을 메모리에 로드 시킬것인가를 결정합니다. 또하나는 short-term scheduler 또는 cpu-scheduler라고 하며 이것이 바로 레디큐에서 어떤 것을 디스패치 시킬 것 인가를 결정하게 됩니다. 이둘의 가장 큰 차이점은 결정의 빈도에 있다고 할수 있는데, 숏텀 스케줄러의 경우 프로세스당 100밀리초 마다 실행이 되어야할 경우(프로세스당 CPU점유 시간) 10밀리초가 걸린다면 매 프로세스 실행시간의 9%를 단지 다음번 프로세스를 결정하는데 사용하는 결과를 초해하게 되지요. 이와 달리 롱텀은 정말 멀티프로그래밍의 정도 (얼마나 많은 프로세스를 생성하는가)에 따라 그 빈도가 비교적 천천히 발생하는 여유를 가지고 있습니다.프로세스 스케줄링 논할때 롱텀과 숏텀 스케줄링 이렇게 두개만을 여기서는 소개했지만, 로써 멀티프로그래밍의 정도, 즉 씨피유및 메모리의 부하를 줄이는데 사용되는 기법인데 다른말로는 스와핑(swapping)이라고도 합니다. 이는 메모리 스케줄링에서도 등장하는 말인데 메모리에 프로세스를 올리는 스왑인(swap in), 메모리에서 프로세스를 제거하는(완전히 지우는 것이 아니라 하드디스크같은 기억장치에 보관을 하게 되지요) 스왑아웃(swap out)등이 있어요.CPU가 한 프로세스를 실행하다가 실행하던 프로세스의 상태를 저장하고, 또 다른 프로세스로 순간적으로 전환해서 실행을 하는 것이 멀티프로그래밍의 원리인 것입니다. 컨텍스트 스위칭이란 바로 CPU가 그렇게 프로세스를 전환하는 순간을 일컫는 말인데요, 문제는 이것이 정말 순수한 오버헤드라는 사실입니다. 멀티프로그래밍을 구현하기 위하여, 본래의 프로세스들의 내용과는 관계없이 그냥 이루어지는 것이기 때문입니다. 컨텍스트 스위칭은 OS 자체보다는 하드웨어적인 환경에 더욱 영향을 많이 받게 되죠. 이 컨텍스트 스위칭은 한 시스템의 성능을 평가함에 있어서 병목현상의 주된 원인이 되기도 해요. 그래서 이제는 프로세스들 끼리는 필연적으로 컨텍스트 스위칭을 필요로 한다는 사실을 극복하려는 과정에서 태어나는것이 바로 그 이름도 유명한 쓰레드(thread)입니다.2. 쓰레드프로세스는 자신이 사용하는 리소스와 실행이 되고있는 장소에 의해서 정의될수 있으며 차일드 프로세스가 생성될시에는 패런트 프로세스로 부터 모든 변수및 상태를 로컬로 복사해온뒤 사용을 하게 됩니다. 또한 이때 프로세스간에는 글로벌 변수란 의미가 없어지기에 특별히 공유 메모리(shared memory), 세마포어(semaphore), 그리고 메시지(message)같은 IPC(Inter Process Communication)를 이용해서 프로세스 사이의 통신이라는 개념으로 변수를 결과적으로 공유하게 됩니다.만일 우리가 새로운 프로세스의 생성을 위해서 fork()라는 시스템콜을 이용했을때 위와 같은 새로운 프로세스의 생성과정과 달리 새로운 프로그램 카운터( 그 무언가가 등장한다고 가정해본다면, 이는 정말 유용한 기법이 됩니다. 바로 그 무언가가 쓰레드의 정체인 것이죠. 쓰레드는 이와 같이 프로세스와 사뭇 유사한 개념을 가지고 있으면서도 확실히 다른 면모가 있기 때문에 종종 경량이 프로세스(lightweight process-LWP)라고도 불리게 됩니다. 경량이라는 것은 결국 부모의 프로세스로부터 어쩔 수 없이 물려받아 새로이 할당해야만 했던 주소공간을 그냥 직간접적으로 공유해버리는 속성으로부터 나온 말이죠. 쓰레드를 이루는 구성요소는 따라서 프로그램카운터, 레지스터셋, 그리고 스택공간등이며 동료쓰레드(peer thread)들과는 코드섹션과 데이터색션, 그리고 태스크(task)로 총칭되는 시스템리소스를 모두 공유하게 됩니다. 전통적인 프로세스는 다른말로 중량 프로세스(heavyweight process)라고 불리게 되고, 중량에게는 정확히 하나의 쓰레드에 하나의 태스크가 대응이 되지요. 그렇게 주소공간을 공유함으로써 얻는 이익 중에서 가장 눈에 띄는 장점으로써는 쓰레드는 프로세스와 달리 일단 생성시 그리 부하가 걸리지 않는 다는 것입니다. 로컬 메모리 할당을 추가적으로 하지 않으니까요. 또한 쓰레드간의 전환시 레지스터 수준에서의 스위칭이 필요하기는 하지만 프로세스간에 전환하면서 일어나는 컨텍스트 스위칭(context switching)에 비해서는 메모리 관리에 관련된 작업이 거의 일어나지 않으므로 신속한 전환이 가능하죠.쓰레드를 시스템에서 구현할 때에는 크게 두가지 방법을 사용하게 됩니다. OS 커널 수준에서 직접 구현하는 방법과 유저레벨(user-level)에서의 인스톨인데 후자는 직접적인 시스템 콜을 이용하지 않고 쓰레드에 관련된 라이브러리를 이용하게 됩니다. 따라서 유저레벨 쓰레드의 경우는 쓰레드간의 스위칭시 OS로의 시스템콜을 날리지 않기에 커널 수준에서의 인터럽트 또한 발생하지 않는 장점을 가지고 있지만, 커널 자체가 단일 쓰레드로 이루어져있는 경우 유저레벨에서 특정 쓰레드가 시스템콜을 할 때 그 콜이 됩니다.
■ 유효범위변수가 그의 값을 올바르게 행사할 수 있는 활동지역을 변수의 유효영역(variable scope)이라고 한다. 즉, 변수가 한 블록에 선언되면 해당 블록에서만 유효하다. 블록은 또 다른 블록을 자신 안에 내포할 수 있어서 유효지역이 중첩될 수도 있다. 따라서 변수는 중첩된 블록의 유효지역에 따라 지역변수(local variable), 비지역변수(non-local variable)와 전역변수(global variable)로 구분된다.아래 프로그램에서 block2에 선언된 변수 a2, b3, c3의 활동영역은 block2이고, block1에 선언된 변수 a2, b2, c2의 유효영역은 block2에까지 이른다. block1과 block2에서 동시에 선언된 변수 a2는 동일한 기억장소가 아니다. 따라서 a2는 block2에서 2를 block1에서 12의 값을 갖는다. 그리고 block2의 b3은 block1에서 유효하지 않기 때문에 상위 블록 block1에서 출력시킬 수 없다.main(){ int a1=10, b1=20, c1=30; /* main 블록 */{ int a2=12, b2=22, c2=32; /* block1 */{ int a2=2, b3=3, c3=4; /* block2 */printf("%d %d}printf("%d %d}printf("%d %d}위에서 가장 밖에 있는 블록에 선언된 변수 a1, b1, c1을 전역변수(global variable)라 하고, 가장 내부에 선언된 변수 b3, c3을 지역변수(local variable)라 하며, 그 중간에 위치한 블록 즉, 외부블록과 동시에 내부에 또 다른 블록을 포함하고 있는 블록의 변수 b2와 c2는 비지역변수(non-local variable)라고 한다.상수는 프로그램에서 변하지 않는 값에 부쳐진 이름이다. 상수는 이름 자체가 값이라는 점 이외에는 변수와 동일하게 해석된다. 상수에는 실행하기 전 번역시간에 계산되는 정적 상수(static constant)와 실행도중에 계산되는 동적 상수(dynamic constant)로 구별되는데 동적 상수는 값을 실행시간에 결정한다는 점 이외에는 정적 상수와 마찬가지로 결코 값이 변경되지 않는다.예를 들면 PASCAL에서 const a=10;은 정적 상수의 선언이고, const x=a+3.14;는 실행시간에 값이 결정되는 동적 상수의 선언이다.■ 유효영역에 대한 규칙(scope rule)블록구조의 언어에서 변수나 상수는 선언된 블록에서만 유효하다. 따라서 서로 다른 블록에서는 동일한 변수명이 작성될 수 있다. 다른 블록에서 선언된 변수들은 비록 이름이 같다할지라도 동일한 기억장소를 의미하지 않는다. 이런 규칙은 기억 클래스(storage class)의 사용으로 변경될 수 있다.예를 들면 위 프로그램에서 변수 a2는 block1과 block2에서 두번 선언되어 있다.■ 배정문주로 변수의 값은 배정문으로 변경시키는데 배정방법은 일반적으로 식(expression)을 계산하여 값을 변수에 복사시키는 방법을 취한다.x=expression;만약 배정문에서 x=y;처럼 수식이 하나의 변수명으로 구성되어 있으면, y의 값을 x의 장소에 복사하는 방식이 된다. 이때 x는 주소를 의미하고 y는 값을 의미하기 때문에 y 변수의 값을 r-value(right-hand side value), x의 주소를 l-value(left-hand side value)라고 한다. 즉 배정문에서 r-value의 값은 l-value에 의하여 간접적으로 참조된다.이 밖에 배정문은 포인터 개념아래 해석될 수 있다. 예를 들면 배정문 x=y;을 수행할 때, y의 주소를 x에 복사하는 바인딩 방법으로 하거나, y의 값을 일시적인 기억장소에 복사해 두고, 그 주소를 x에 바인딩하는 경우로 설명할 수 있다.■ 함수의 유효영역변수의 유효영역에 대한 규칙(scope rule)은 함수에도 적용되는데 함수의 중첩을 허용하는 프로그래밍 언어에서 함수의 유효범위에 대한 규칙은 일반변수와 같다. C 언어에서는 함수 안에 중첩해서 함수를 정의 할 수 없고, 모든 함수는 main() 함수와 대등한 수준에서 독립적으로 작성되기 때문에 모든 함수는 전역(global) 함수로 사용된다. 하지만 함수 안에 특정한 함수의 정형을 선언함으로서 지역(local) 함수로 지정할 수 있다.{/* 함수의 유효영역 */main() {int maxx(int, int, int); /* 정형선언으로 maxx()는 지역함수*/}int maxx(int a1, int a2, int a3) /* 3수 중에서 가장 큰 수를 찾는 함수 */{ int max;if (a1>a2)max=a1;elsemax=a2;if (a3>max)max=a3;return max;}■ 자바에서의 변수의 유효영역변수의 유효 범위란 그 변수에 접근이 가능한 코드들의 블록을 의미하고, 변수의 종류에 따라 변수의 유효 범위가 지정된다.
문제) 현재 시스템의 표현 가능한 양의 정수값의 최대값과 음의 정수값의 최소 값을 표현을 C로 작성하시오.1 C Program List/******************************************//* 현재 시스템의 표현 가능한 양의 정수값의*//* 최대값과 음의 정수값의 최소 값을 표현 *//* *//* 학번 : 9674006 *//* 이름 : 김 성 진 *//* 날짜 : 2002.3.21 *//******************************************/#include main(){int nIntLen;int nMulti = 1;int nMaxInt, nMinInt;nIntLen = sizeof(int) * 8/*bit*/;// 현재 정수형의 bit사이즈 취득/* 2의 n-1승을 계산 */for(int i=1; i