본문 바로가기
코스웨어/12년 내장형하드웨어

9월 20일 업무일지 - 김동기

by 알 수 없는 사용자 2012. 9. 21.
728x90
반응형

64page 소스분석

 

unistd.h에 정의 되어 있는 read를 사용한다. 이를 사용하기 위해서 <unistd.h> 파일을 include시킨다.   원형은 ssize_t ret (int fd, void *buf, size_t len); 이고,

성공시 0 실패시 -1을  반환하고, errno을 설정한다. 이를 perror을 이용해서 출력한다.

결과 창에 파일을 기술 할수 없다는 메세지가 나타나는 것을 확인 할 수 있다.

 

만약 성공시 받을 크기(len)와 받은크기(ret)가 같으면 len이 0이 되고, 빠져 나온다.

아닐시 len-ret = len 나머지 읽을 계수를 세팅하고, 파일 포인터를 읽지않은 곳까지 이동시키는 코드이다.

이때, while문을 빠져 나올때, 두 조건을 모두 거짓으로 만들어 버리면서 나온다. 이 점을 한번 알아 보도록 하자.

 

int i =100;

if ( 0 && ++i )                             if ( 1 && --i)
{                                              {
  코드                                              코드                                                        

}                                              }
printf("%d\n", i);


위의 코드를 실행 시켜서 i를 출력하면, i는 100이란 값을 유지 한다. 이는 컴파일러가 앞의 조건이 0,1에 따라 결과가 명백한 참, 거짓이기 때문에 뒤의 조건을 수행하지 않는다.

 

다른 말로 컴파일러가 소스를 왜곡 한다고도 말할 수 있다. 이처럼 최적화에 따른  컴파일러의 왜곡을 고려 해야 한다. (최적화 ==  왜곡) 만약 컴파일러의 왜곡에 따른

명백한 이유를 알고 싶은 경우, 중간파일 생성, 어셈블리 언어를 보고 어느 정도의 파악이 가능하다. 

 

또, 양날의 검으로 최적화가 되면, 그만큼 왜곡이 일어난다. 장단점이 있다는 이야기다. 

최적화의 단계가 나눠져 있다. 컴파일 옵션 최적화 옵션을 주면, 조절 할 수 있다. gcc에서는 대문자 -O -O1~ O2 옵션을 사용한다. 의도에 따라서 맞게 사용한다.

 

키보드로 부터 글자를 입력 받아 출력하는 프로그램을 read함수를 사용해서

read함수의 또다른  특징을 알아보자

 

먼저 man 페이지를 열어 보면, <unistd.h>헤더에 있으므로 include시키자, 다음으로 반환형이 ssize_t 로 typedef(_)으로 int형이고 읽을 글자 계수를 반환한다 는 설명이 나와 있다.

 이를 이용하여, printf로 출력을 해보자.

 

 

 

 

이때, 문자열을 완성시키기 위해 마지막에 \0을 추가 시켜 %s로 출력을 시키면,

 

 

 

위와 같이 read가 읽어 들인 \n과 printf의 \n이 출력 된 결과를 확인 할 수 있다.

 

 read는 엔터까지 읽는다는 것을 확인 할 수 있다. 이를 해결하기 위해서 읽은 계수에서 -1의 자리 (\n) 자리에 \0넣어 문자열을 완성하면 제대로 된 결과가 출력 된다.

 

 

 

이처럼 함수에 따라서 \n을 읽는 함수, \0넣고, \0은 빼고, 다양함이 존재 한다 이럴때는 문자열 출력시 []로 감싸서 확인한 후 사용한다. (팁)

 

 read는 일종의 플로킹이다.  지금은 입력이 있을 경우, 파일에서 읽을 때 까지 프로그램진행을 막고 이다.

 

read()에서 크기 제약

size_t 와 ssize_t에서 _t t는 typedef 의 t로서, 각각

typedef       unsigned int     size_t   

typedef       signed int         ssize_t   

로  <limits.h> <stdint.h> 헤더 안에  디파인 되어 있다.

         

size_t      ssize_t 를 쓰는이유는 만약 변수의 자료형 (크기)를 늘리고 싶을 경우  long라고 바꾸면 된다.  프로그램의 유용성을 증가 시킬 수 있는 것이다.

 

size_t의 최대값은 SIZE_MAX ,   ssize_t의 최대값은 SSIZE_MAX이다. 이를 printf함수를 사용해서, 출력해 보자.

 

 

길이는 양수로 unsigned 4byte int를 나타낼 unsigned long형식 지정자 %lu를 사용해야 한다.

 

이는 unsigned int / signed 최대를 나타내는 헤더 이므로 중요하다. 기억 하도록 하자.

 

 

 

 

이제 첫번째 파일을 열어 write 함수로 buf를 출력해 보자.

 

 

 

오류내용 분석

 

putchar 함수 안 static 변수가  버퍼가 다차야 출력한다. 예외적으로 다차지 않아도, \n 개행문자를 만나면 출력한다. write함수는 저수준으로 버퍼를 사용하지 않고 직접적으로 시스템을 호출 하므로 먼저 출력 된다.

그 후, 버퍼에 []를 담은 후 \n만나서 출력 된다.

 

이와 같이 우리가 원하는 입출력을 하기 위해서는 사용하는 함수가 버퍼를 사용하는지 하지 않는지를 고려해 봐야 한다.

 

putchar은 고수준 출력으로 고수준은 효율을 중요하게 생각 한다. (버퍼가 다 차야 = 버스에 사람이 다 타서 출발해야 에너지로 보면 효율적) 대신, 속도가 느린 단점이 있다.

 

이를  해결하기 위해서 fflush() 로 버퍼에 남아 있는 문자를  강제로 출력 시킨다.

read, write,fflush같은 함수는 저수준 입출력으로 시스템 호출, 바로 바로 출력 한다.

 

 

 

덧붙이기 모드 (O_APPEND)

 

 read,write함수는 파일을 읽고 쓸때 마다 파일 포인트를 이동시킨다, 작업이 끝나면, 다시파일을 열면 처음 위치로 되돌아 온다. 이를 그림으로 나타내면,

 

 

 

다음과 같다 두번 read를 해도 속성을 주지 않으면 buff에 같은 결과가 입력된다.

특정한 위치 이동시에는 lseek 함수를 , APPEND속성의 파일포인트는 eof에 위치하여 쓰고, 읽을 수있다. 

 

 

동기식 입출력

 

cpu에서 하드 디스크로 저장할때,레지스터는 용량이 적고, 그나마 속도나 용량이 나은  sdram렘으로 모아서(버퍼기능) 한꺼번에 저장한다.

전에 putchar 함수 처럼 저장할때를 마음대로 조절할 수 없다. 함수들을 이용해서, 안전하게 저장시점을 조절 할수 있다.

 

 

fsync()와 fdatasync()

 

fsync()함수는 <unistd.h>파일에 include 되어 있고,  int fsync(int fd); 로 정의 되어 있다.

 

사상 mapping 연결되어 있다.

 

되어 있는 (인자의)파일과 관련된 모든 정보를 디스크에 쓰도록 보장한다.

 

하드디스크 뒤에 보면 하드디스크를 제어하는 cpu와 자료손실을 방지하기 위한 임시정장 메모리 캐시 라고 부른 곳이 있다.

 

fsync()는 하드 디스크가 자료와 메타자료를 썼다고 알려줄 때까지 기다린다.

캐시가 있으면, 자료들이 캐시에 있을지 모르지만, 캐시에 들어 있는 자료는 짧은 시간 안에 저장된다.

 

메타자료 : 만약 .avi 파일의 영상/소리 데이터외에 이 데이터에 대한 정보들

크기, 코덱, 시간, 헤더 등 데이터를 위한 데이터

 

fdatasync()함수는

 #include <unistd.h>

int fdatasync (int fd); 로 정의 되어 있고, fsync()와 동일 하지만,

fdatasync는 자료만 강제적으로 기록, 메타자료를 디스크에 동기화 하도록 보장하지 않으므로, fsync()보다 더 빠르다.

 

속성 이나  정보 같은 부수 적인메타 데이타 가 손실 될수 있다. fdatasync

연 파일의 경로에 락을 걸어 줘야 한다. 방법은 나중에

 

sync()

#include <unistd.h>

void sync(void);

로 반환 값과 인자가 없다. 이는 동작할때, 버퍼의 내용을 저장하도록 시작을 요구할 뿐,

디스크에 다 쓸때까지 기다리도록 요구 하진 않는다. 반환값이 없으므로, 완료 될때까지.

보장하는 방법을 생각해야 한다.

=> 여러번  함수 호출을 하거나, for를 걸어 지연 시켜 준다.

 

복습 //부팅, 하드디스크

먼저 컴퓨터가 실행되면, BIOS 가실행되고,nt로더등의 로더를 메로리에 올린다.

로더는 MBR(섹터0, 트렉0)에 있는 부트 섹터를 실행 (운영체재를) 실행 시킨다.

 

 

 

 

 여기서, 리눅스는 liloder등 여러가지 로더들이 있다. 반면,

윈도우는 ntloder로더 하나 뿐이다.  /리눅스든 윈도우든 로더등으로 다른 운연체제를 부팅을 가능하게 하는 멀티부팅이 가능하다.  (30초동안 표시 됩니다. 하면서 운영체제를 선택하는 화면을 본적이 있을 것이다. )

 

이를 확인해 보자. 탐색기를 열어 C드라이브 안에 있는 boot.ini파일을 메모장으로 열어 보면,

 

boot.init 확인

시간

하드드라이브

부팅 디렉토리  등의 정보가 나타난다.

 

 

포멧에 대한 정보를 확인해 보면 하드디스크이 구조에 대한 정보를 알수 있는데

 

 

NTFS

용량이 커지면서 이를 접근하기 위한 주소가 부족해 진다. 이와 함께 디테일 하고, 보안 개념등 더 낳은 방식의 파일시스템을 말한다.

FAT

기존의 파일 시스템으로

 

할당 단위 크기

 

4096 값은 한섹터의 한 트랙을 나눈하나의 값의 크기 (조각모음에서 네모 하나의 크기) 4kbyte 정도로 표시 되어 있는 것을 알 수 있다 이를 사용 하는 이유는,

 

 

그림과 같이 한칸이 4kbyte인 섹터에 첫 번째와 같이 데이터가 있을 경우에서 파란색 데이터만 남기고, 지우고, 다시 12kbyte를 써야 하는 경우에  문제가 발생한다.

 

 기존의 데이터를 밀어 내고 데이터를 쓸경우 속도가 느려지는 반면, 나누어서 데이터를 쓸경우, 속도는 빠르지만 연결 되어 있지않아 사용할 수 없게 된다.

 

이를 해결하기 위해 하나의 할당된 크기에 데이터 양쪽에 연결된 곳의 정보를 가르키는 공간을 만들어 연결해 놓았다 우리가 잘 알고 있는 연결 리스트가 쓰이는 것이다.

 

이 또한 문제가 없는 것은 아니다. 만약 용량이 작은 하드에 1k 텍스트를 만들경우 3k 는 낭비가 생긴다. 이런 것이 많아 지면, 엄청난 낭비가 발생할 것이다.

 

 

반대로 너무 짤게 나누면, 본래의 일보다, 쓸데없는 (주목적으로 보았을때) 연결리스트 역활을 하면서, 느려질 것이다.

 

그러므로 FAT는 적은 값으로 용량이 큰 NTFS는 높은 값으로 고려하여 선택한다. 

 

 

포멧의 종류

포멧은 들어 있는 값들은 건들지 않고, 다시 구역을 나눈다. 

로우 포멧 일정의 값을 넣어서 기존의 값을 못쓰게 한고, 다시 구역을 나눈다.

 

 

 

다중 입출력

 

int a;                                              stdin     0

int b;                                              stdout   1

 stderr    2

a = open(" ",.....);                            a 4      

b = open(" ",.....);                            b 5

while(1)

{

read(a,  ,10);

read(0,  ,100);

}

위의 소스에서 두 파일을 열고, read로 두 파일중 먼져 들어오는 파일의 정보를 받기를 원한다. 그러나 c프로그램은 순차적이므로, 첫번째, read에서 블로킹 되고 있으면, 두 번째, read가 실행 되지 않는다. 

 

먼저 오는 것을 받을 수 없다.  컴퓨터는 마우스 키보드 화면 중 먼저 오는 입력을 선택해서, 받는데, 앞으로 배울 함수를 통해서 베워 보자. 네트워크나 시리얼 통신에 쓰이는 개념으로 중요하다.

728x90