fsetpos, fgetpos 함수

Programming/C 2013. 2. 15. 03:41 |

fsetpos : fseek함수 보다 더 큰 파일을 다루는 함수.


: fseek 함수의 문제점은 다룰 수 있는 파일의 크기가 long형으로 제한된다는 점이다. 따라서 이러한 제약사항의 보완을 위해서 C 표준에는 fsetpos라는 이름의 함수가 추가되었다.


#include <stdio.h>

int fsetpos(FILE* stream, const fpos_t* pos);

성공 시 0, 실패 시 0 아닌 값 반환


fsetpos 함수는 "stream이 가리키는 파일의 위치 지시자를 포인터 pos가 가리키는 변수에 저장된 값만큼 이동시켜라" 라는 함수이다.




fgetpos : ftell함수 보다 더 큰 파일을 다루는 함수.


:ftell함수가 지니고 있는 제약사항의 보완을 위해 표준에 추가된 함수이다.


#include <stdio.h>

int fgetpos(FILE* stream, const fpos_t* pos);

성공 시 0, 실패 시 0 아닌 값 반환


fgetpos 함수는 "stream이 가리키는 파일의 위치 지시자 정보를 포인터 pos가 가리키는 변수에 저장하라." 라는 함수이다.


§ fsetpos함수와 fgetpos함수를 이용한 예제.



※ fsetpos, fgetpos를 사용하면 long형의 범위를 넘어서는 대용량 파일의 경우에도 동작한다.


Posted by scii
:


'Programming > C' 카테고리의 다른 글

표준 입력 및 출력 그리고 에러의 리다이렉션  (0) 2013.02.15
fsetpos, fgetpos 함수  (0) 2013.02.15
fread, fwrite 함수  (1) 2013.02.15
조건부 컴파일(Conditional Compilation)  (0) 2013.02.15
#error, #pragma 및 #line  (0) 2013.02.15
Posted by scii
:

fread, fwrite 함수

Programming/C 2013. 2. 15. 03:38 |

바이너리 데이터의 입출력 : fread, fwrite

이 함수들은 바이너리 데이터의 입출력에 사용이 된다. 



fread

#include <stdio.h>

size_t fread((void*) buffer, size_t size, size_t count, FILE* stream);

성공 시 전달인자 count, 실패 또는 파일의 끝 도달 시 count보다 작은 값 반환.


ex) int buf[12];

ex) fread((void*)buf, sizeof(int), 12, fp);

fread 함수는 두 번째 전달인자와 세 번째 전달인자의 곱의 바이트 크기만큼 데이터를 읽어 들이는 함수이다.

따라서 위의 문장은 "int형 데이터 12개를 fp로부터 읽어 들여서 배열 buf에 저장하라" 라는 뜻이 된다.


이 함수는 실제로 읽어 들인 개수를 반환하는데(바이트 수가 아니라 개수이다.) 위 문장은 sizeof(int) 크기의 데이터를 12개 읽어 들이는 경우이니, 함수의 호출이 성공을 하면 12가 반환된다. 그리고 만약에 12보다 작은 값이 반환된다면 파일의 끝에 도달을 해서 12개를 채우지 못했거나, 오류가 발생한 상황으로 인식할 수 있다.



fwrite

#include <stdio.h>

size_t fwrite((void*) buffer, size_t size, size_t count, FILE* stream);

성공 시 전달인자 count, 실패 시 count보다 작은 값 반환.


ex) int buf[7] = {1, 2, 3, 4, 5, 6, 7};

ex) fwrite((void*)buf, sizeof(int), 7, fp);

"sizeof(int) 크기의 데이터 7개를 buf로부터 읽어서 fp에 저장하라" 라는 뜻이 된다.




※ 바이너리 데이터를 읽을 때에는 일반적으로 char형 배열을 사용한다. char는 모든 시스템에서 1바이트로 처리되므로 크기를 지정하기가 수월하기 때문이다.



20행 : if문은 fread 함수가 BUF_SIZE보다 작은 값을 반환했을 때 참이 된다. 그런데 fread 함수가 BUF_SIZE를 반환하지 않았다는 것은 오류가 발생했거나, 파일의 끝에 도달했다는 의미가 되므로 feof 함수를 이용해서 이를 확인해야 한다.


24행 : 파일의 끝에 도달해서 BUF_SIZE보다 적은 수의 바이트를 읽었을 때 실행이 된다. 비록 적은 바이트를 읽었다 할지라도 이 데이터 역시 파일의 일부분이므로 fwrite 함수를 이용해서 복사를 해줘야 한다. 따라서 24행에서 fwrite 함수의 호출을 통해 읽어 들인 마지막 데이터를 출력하고 있다.


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







※ 구조체 변수의 데이터를 통째로 바이너리 형태로 저장할 수 있는 이유는, 구조체 변수의 데이터를 통째로 바이너리 형태로 읽어 들이기 때문이다.


Posted by scii
:

#if... #endif : 참이라면

: if 매크로는 '참'이냐 '거짓'이냐를 기준으로 동작.






#ifdef... #endif : 정의되었다면

:ifdef 매크로는 "정의되었느냐(참)", "정의되지 않았느냐(거짓)"를 기준으로 동작.




이 매크로는 정의되었느냐를 판단하기에 옆에 참 거짓을 의미하는 1과 0을 생략한다.




#ifndef...#endif : 정의되지 않았다면

※ #ifndef는 헤더파일의 중복포함을 막기 위해 주로 사용이 된다.





#if와 함께 사용할 수 있는 "defined" 연산자

: defined 연산자는 매크로 #if문의 구성에 활용할 수 있는 연산자이다. 이 연산자의 덕분으로 #if문에서도 매크로의 정의 유무를 확인할 수 있게 된다.




defined 연산자 덕분에 코드가 한결 간결해졌다.




#undef : 이전에 정의된 매크로를 무효화




매크로 DATE를 무효화시키고 있다. 무효화시킨다는 것은 전처리기의 기억에서 지우는 것을 의미한다. 그런데 앞서 매크로  DATE가 정의된 적이 없다. 하지만 이는 오류가 아니다.

#undef는 정의되지 않은 매크로의 무효화 명령에도 오류를 발생시키지 않기 때문이다. 따라서 정의 유무가 확실하지는 않지만, 무효화시켜야 할 매크로가 있다면 언제든지 #undef 명령문을 구성하면 된다.


※ 매크로의 무효화 과정 없이도 재정의는 가능하다. 그러나 경고메시지가 발생하므로 무효화 과정을 거치는 것을 권장.


Posted by scii
:

ANCI C에는 #error와 #pragma가 있다.

#error
#if A_LENGTH > B_LENGTH
    #error "Unmatched Length"
#endif
컴파일 중 #error 지시자를 만나면, 그 뒤의 문자열이 화면에 출력된다.



#pragma

#pragma 지시자는 다음과 같이 사용하며, 특정 C컴파일러에 따라 그 효과가 다르다.
#pragma 토큰들

#pragma는 컴파일러에게 정보를 전달하기 위해서 사용이 되는 매크로 지시자이다. 그런데 컴파일러마다 지원하는 #pragma 지시자의 구성에 차이가 있다. 그래서 일괄적으로 설명하는 데에는 무리가 있다.

ex) #pragma warning(disable:5555) //VC에서만 유효.

이 문장은 VC++ 컴파일러에게 다음과 같은 메시지를 전달하는 매크로 명령문이다.
"5555번 경고 메시지는 그냥 뿌리지 마세요."


#line
#line은 원래의 파일명과 줄 번호 대신에 그 위치에 임시 파일명과 줄 번호를 부여하는 지시문이며, 그 형식은 다음과 같다.
#line 줄번호 "파일명"

이 #line은 다음 줄의 번호를 바꾸고, 현 파일명이 마치 바뀐 것처럼 취급한다. 컴파일러가 발견한 에러 메시지 속에 에러 장소를 나타내기 위해 지정한 파일명과 줄 번호가 채택된다. 이러한 #line 사용 예는 다음과 같다.
.
.
.
10  a = int;
11  #line 100 "error.c"
12  c=(d+e;
.
.
.
에러 메시지:
program.c line 10  ... syntax error ...
error.c   line 100 ... stntax error ...

이 예에서 10,11,12는 program.c의 줄 번호를 나타내고 있는데, 줄 번호 11의 #line지시로 줄 번호가 100으로 재지정 되었으므로 줄 번호 12의 에러는 error.c에 줄 번호 100으로 취급된다.

'Programming > C' 카테고리의 다른 글

fread, fwrite 함수  (1) 2013.02.15
조건부 컴파일(Conditional Compilation)  (0) 2013.02.15
매크로와 전처리기 (Preprocessor).  (0) 2013.02.15
실행파일이 만들어 지는 과정.  (0) 2013.02.15
sprintf 함수, sscanf 함수  (0) 2013.02.15
Posted by scii
:

전처리기 : 소스코드는 컴파일러에 의해서 컴파일 되기 이전에, 전처리기라는 것에 의해서 전처리기 과정을 거치게 된다.

전처리기가 하는 일 : 단순히 치환(substitution)의 형태를 띠는 경우가 대부분.



#define : Object-like macro


#define PI 3.14


int main()

{

      .....

      num = PI * 3.5; // 전처리기로 전처리 과정을 거치게 되면 num = 3.14 * 3.5 가 된다.

      ....

}


전처리 명령문은 # 문자로 시작을 하며, 컴파일러가 아닌 선행처리기에 의해서 처리되는 문장이기 때문에 명령어의 끝에 세미콜론을 붙이지 않는다.


#define  PI  3.14

 ↑지시자                              ↑매크로      ↑매크로 몸체('매크로 상수'라고도 불림.)


결과적으로 PI라는 이름의 매크로는 그 자체로 상수 3.14가 된 셈이다. 참고로 PI와 같은 매크로를 가리켜 '오브젝트와 유사한 매크로(object-like macro)'라 한다.


 오브젝트(object)라는 것은 그 자체로 "완전한 의미를 갖는 대상이나 사물"을 의미한다. 그런데 위에서 정의한 매크로 PI는 그 자체로 3.14라는 상수를 의미하기 때문에 "오브젝트와 유사한 매크로" 라고 한다.




※ 매크로는 대문자로 정의하는 것이 일반적이다. 대문자로 정의함으로 인해서 변수나 함수의 이름과는 쉽게 구분이 되고, 이 식별자가 매크로라는 사실을 부각시킬 수 있기 때문이다.




#define : Function-like macro


(매크로 함수)


: 매크로는 매개변수가 존재하는 형태로도 정의할 수 있다. 그리고 이렇게 매개변수가 존재하는 매크로는 그 동작방식이 마치 함수와 유사하여 '함수와 유사한 매크로(function-like macro)' 라 하는데, 줄여서 "매크로 함수" 라고도 부른다.



#define  SQUARE(X)   X*X

                                  ↑이러한 패턴 등장 시                         ↑이러한 유형으로 바꿔라       


위의 정의를 접한 전처리기는 SQUARE(X)와 동일한 패턴을 만나면, 무조건 X*X로 치환해버린다.


매크로 확장(macro expansion)




※ 기본 적으로 매크로는 한줄에 정의하는 것이 원칙이다. 하지만 가독성을 높이기 위해서 두 줄에 걸쳐서 매크로를 정의할 수 있다.

이럴땐 \문자를 활용해서 줄이 바뀌었음을 명시해야 한다.

#define SQUARE(X) \

           ((X)*(X))





매크로 정의 시, 먼저 정의된 매크로도 사용 가능.



매크로 함수의 장점


:매크로 함수를 정의하는 것은 일반 함수를 정의하는 것보다 어렵다. 그리고 정의하고자 하는 함수의 크기가 크면, 매크로로 정의하는 것 자체가 불가능할 수도 있다. 그럼에도 불구하고 함수를 매크로로 정의하는 이유는?


1. 매크로 함수는 일반 함수에 비해 실행속도가 빠르다.  (일반 함수는 호출된 함수를 위한 스택 메모리의 할당, 실행위치의 이동과 매개변수로의 인자 전달, return문에 의한 값의 반환이 일어난다. 그래서 일반 함수의 빈번한 호출은 실행속도의 저하를 가져온다.)


2. 자료형에 따라서 별도로 함수를 정의하지 않아도 된다. (SQUARE를 보면, 전달인자의 자료형에 상관이 없음을 알 수 있다. 이 모두가 매크로 함수의 호출 문장이 매크로 함수의 몸체 부분으로 단순히 치환되기 때문에 가능한 일이다.)



매크로 함수의 단점


1. 정의하기가 까다롭다.


#define DIFF_ABS(X, Y)  ((X) > (Y) ? (X)-(Y) : (Y)-(X)) 삼항 연산자를 활용하였는데..

if~else 문으로 바꾸면 이렇다.


int DiffABS(int a, int b)

{

      if(a>b)

            return a-b;

      else

            return b-a;

}




2. 디버깅하기가 힘들다. (매크로를 잘못 정의할 경우, 에러 메시지는 선행처리기를 기준으로 출력되지 않고, 컴파일러를 기준으로 출력이 된다. 따라서 일반적인 에러 메시지보다 이해하기 힘들다.)




매크로 함수의 장점과 단점을 종합한 결론.


ⓐ 함수의 크기 또는 길이가 짧은 함수. (함수의 크기 또는 길이가 짧아야 매크로의 형태로 정의하기가 편리하고 에러의 발생 확률이 낮아서 디버깅에 대한 염려를 덜 수 있다.)


ⓑ 호출이 되는 빈도수가 높은 함수. (호출의 빈도수가 높아야 매크로 함수가 가져다 주는 성능 향상의 이점도 최대한 누릴 수 있다.)


Posted by scii
:

소스파일

전처리기

전처리를 거친 소스파일

컴파일러

obj파일(binary code)

Linker

실행 파일


Posted by scii
:

printf 함수와 scanf 함수의 입출력 대상은 콘솔인 반면, sprintf 함수와 sscanf 함수는 입출력 대상이 문자열 배열이다.

이 함수들은 아주 유용하게 사용이 되는 함수들이다.



sprintf 함수 : 출력이 대상이 메모리 공간.


printf 함수는 만들어진 문자열을 모니터로 출력하는 반면, sprintf 함수는 문자열 배열에 출력을 한다(저장을 한다).

따라서 sprintf 함수는 첫 번째 전달인자로, 출력의 대상이 되는 문자열 배열의 주소 값 정보가 전달되도록 정의되어야 한다.


#include <stdio.h>

int sprintf(char* restrict s, const char* restrict format, ...);

성공 시 저장된 문자열의 길이, 실패 시 EOF 반환.




※ printf 함수는 문자열을 모니터로 출력할 뿐이고, sprintf 함수는 첫 번째 인자로 전달된 문자열 배열에 출력(저장)할 뿐이다.





sscanf 함수 : 입력의 대상이 메모리 공간


scanf 함수가 키보드를 통해 데이터를 입력 받는 함수라면, sscanf 함수는 문자열 배열로부터 데이터를 입력 받는(추출하는) 형태의 함수이다.


#include <stdio.h>

int sscanf(char* s, const char* restrict format, ...);

성공 시 읽어 들인 데이터의 개수, 실패 시 EOF 반환.


: scanf 함수는 키보드로부터 데이터를 입력 받는다. 그러나 sscanf 함수는 첫 번째 인자로 전달되는 문자열이 키보드의 입력을 대신한다.




※ scanf 함수는 키보드로부터 입력을 받고, sscanf 함수는 첫 번째 인자로 전달된 문자열로부터 입력을 받는다.


Posted by scii
: