도입 문구
C언어에서 파일 입출력과 시간 기록 기능을 추가하는 방법을 소개합니다. 이 기능은 데이터 저장 및 성능 측정에서 중요한 역할을 합니다.
C언어에서 파일 입출력의 기본
C언어에서 파일 입출력은 외부 데이터와 프로그램 간의 상호작용을 가능하게 합니다. 이를 통해 사용자는 프로그램이 실행 중에 데이터를 저장하거나 불러올 수 있습니다.
파일 입출력의 중요성
파일 입출력은 데이터를 영구적으로 저장하거나, 프로그램이 실행될 때 외부 데이터를 읽어오는 데 필수적인 기능입니다. 예를 들어, 사용자의 입력을 파일에 저장하거나, 파일에서 특정 데이터를 읽어 처리할 수 있습니다.
파일 입출력의 기본 절차
파일을 사용하기 위한 기본 절차는 다음과 같습니다:
- 파일 열기:
fopen
함수를 사용하여 파일을 열고, 읽기 또는 쓰기 모드를 설정합니다. - 파일 작업: 파일에 데이터를 읽거나 씁니다.
- 파일 닫기: 작업이 끝나면
fclose
함수로 파일을 닫습니다.
파일 입출력은 프로그램의 중요한 부분으로, 외부 데이터를 처리하는 데 유용한 도구입니다.
fopen 함수의 사용법
C언어에서 파일을 열 때 사용하는 함수는 fopen
입니다. 이 함수는 파일을 열거나 생성하며, 파일을 어떻게 다룰지 결정하는 모드도 설정할 수 있습니다.
fopen 함수의 구문
fopen
함수는 다음과 같은 구문을 가집니다:
FILE *fopen(const char *filename, const char *mode);
filename
: 열고자 하는 파일의 이름입니다.mode
: 파일을 열 때 사용할 모드입니다. 파일 모드에 따라 읽기, 쓰기, 추가 등의 작업을 할 수 있습니다.
파일 모드 종류
fopen
함수에서 사용할 수 있는 주요 파일 모드는 다음과 같습니다:
- “r”: 읽기 전용 모드 (파일이 존재해야 함).
- “w”: 쓰기 전용 모드 (파일이 없으면 생성, 있으면 덮어씀).
- “a”: 추가 모드 (파일이 없으면 생성, 있으면 파일 끝에 추가).
- “rb”, “wb”, “ab”: 바이너리 모드로 파일 열기.
- “r+”, “w+”, “a+”: 읽기와 쓰기를 동시에 할 수 있는 모드.
예시 코드
다음은 fopen
을 사용하여 파일을 여는 간단한 예시입니다:
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w"); // 파일을 쓰기 모드로 염
if (file == NULL) {
printf("파일 열기 실패\n");
return 1;
}
fprintf(file, "Hello, World!\n");
fclose(file); // 파일 닫기
return 0;
}
이 코드는 “example.txt”라는 파일을 열고, “Hello, World!”라는 내용을 파일에 씁니다.
파일에서 데이터 읽기
파일에서 데이터를 읽는 과정은 fgetc
, fgets
, fread
와 같은 다양한 함수들을 통해 이루어집니다. 각 함수는 파일에서 데이터를 읽는 방식이 다르기 때문에, 필요에 맞는 방법을 선택해야 합니다.
fgetc 함수
fgetc
함수는 파일에서 하나의 문자를 읽어오는 함수입니다. 주로 텍스트 파일에서 한 글자씩 읽을 때 사용됩니다.
구문은 다음과 같습니다:
int fgetc(FILE *stream);
stream
: 읽을 파일의 포인터입니다.- 반환값: 파일에서 읽은 문자(정수형으로 반환됨). 파일 끝에 도달하면
EOF
를 반환합니다.
fgets 함수
fgets
함수는 파일에서 한 줄씩 읽는 데 사용됩니다. 지정한 크기만큼 문자를 읽어 저장합니다.
구문은 다음과 같습니다:
char *fgets(char *str, int n, FILE *stream);
str
: 읽은 데이터를 저장할 배열의 이름입니다.n
: 읽을 최대 문자 수입니다.stream
: 읽을 파일의 포인터입니다.
이 함수는 파일에서 한 줄을 읽고, 줄바꿈 문자를 포함한 문자열을 반환합니다. 만약 파일 끝에 도달하면 NULL
을 반환합니다.
fread 함수
fread
함수는 바이너리 파일에서 데이터를 읽을 때 사용됩니다. 일정 크기만큼 데이터를 한번에 읽어옵니다.
구문은 다음과 같습니다:
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
ptr
: 읽은 데이터를 저장할 메모리 공간의 포인터입니다.size
: 각 항목의 크기입니다.count
: 읽을 항목의 개수입니다.stream
: 읽을 파일의 포인터입니다.
예시 코드
다음은 fgets
를 사용하여 텍스트 파일에서 한 줄씩 데이터를 읽는 예시입니다:
#include <stdio.h>
int main() {
char buffer[100];
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
printf("파일 열기 실패\n");
return 1;
}
while (fgets(buffer, 100, file) != NULL) {
printf("%s", buffer); // 한 줄씩 출력
}
fclose(file); // 파일 닫기
return 0;
}
이 코드는 example.txt
파일에서 한 줄씩 읽어서 출력하는 예시입니다.
파일에 데이터 쓰기
C언어에서 파일에 데이터를 쓸 때는 fputc
, fputs
, fwrite
와 같은 함수를 사용합니다. 각 함수는 데이터 쓰는 방식에 차이가 있으며, 목적에 따라 적합한 함수를 선택해야 합니다.
fputc 함수
fputc
함수는 파일에 한 문자를 쓰는 함수입니다. 주로 텍스트 파일에 하나씩 문자를 쓸 때 사용됩니다.
구문은 다음과 같습니다:
int fputc(int c, FILE *stream);
c
: 파일에 쓸 문자입니다.stream
: 쓸 파일의 포인터입니다.
이 함수는 문자를 하나씩 파일에 쓸 때 유용하며, 반환값으로 쓴 문자를 반환합니다. 실패 시 EOF
를 반환합니다.
fputs 함수
fputs
함수는 파일에 문자열을 쓰는 함수입니다. 문자열의 끝을 나타내는 null 문자(\0
)를 제외한 문자들을 파일에 씁니다.
구문은 다음과 같습니다:
int fputs(const char *str, FILE *stream);
str
: 파일에 쓸 문자열입니다.stream
: 쓸 파일의 포인터입니다.
이 함수는 문자열을 파일에 기록할 때 주로 사용됩니다. 만약 쓰기 실패 시 EOF
를 반환합니다.
fwrite 함수
fwrite
함수는 바이너리 데이터를 파일에 쓸 때 사용됩니다. 데이터의 크기와 개수를 지정하여 한 번에 여러 데이터를 쓸 수 있습니다.
구문은 다음과 같습니다:
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
ptr
: 쓸 데이터의 포인터입니다.size
: 각 항목의 크기입니다.count
: 쓸 항목의 개수입니다.stream
: 쓸 파일의 포인터입니다.
이 함수는 주로 구조체나 배열 같은 바이너리 데이터를 파일에 저장할 때 사용됩니다.
예시 코드
다음은 fputs
를 사용하여 문자열을 파일에 쓰는 예시입니다:
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file == NULL) {
printf("파일 열기 실패\n");
return 1;
}
fputs("Hello, File!\n", file); // 문자열을 파일에 씀
fclose(file); // 파일 닫기
return 0;
}
이 코드는 “example.txt” 파일에 “Hello, File!”이라는 문자열을 기록합니다.
파일 닫기와 오류 처리
파일 작업을 완료한 후에는 반드시 파일을 닫아야 합니다. C언어에서 파일을 닫는 데 사용하는 함수는 fclose
입니다. 또한, 파일 작업 중 발생할 수 있는 오류를 처리하는 방법도 중요합니다.
fclose 함수
fclose
함수는 파일을 닫는 데 사용됩니다. 파일을 닫는 것은 파일에 대한 리소스를 해제하고, 데이터가 제대로 저장되었는지 확인하는 데 중요합니다.
구문은 다음과 같습니다:
int fclose(FILE *stream);
stream
: 닫을 파일의 포인터입니다.
파일을 닫은 후에는 해당 파일 포인터를 다시 사용할 수 없으며, 파일 작업이 끝났다는 신호를 시스템에 전달합니다.
파일 오류 처리
파일 작업 중 오류가 발생할 수 있으며, 이를 적절히 처리하는 방법이 중요합니다. C언어에서 파일 오류를 처리하는 방법은 다음과 같습니다:
- fopen 오류: 파일을 열 때
fopen
함수가 실패하면NULL
을 반환합니다. 이를 체크하여 파일 열기 오류를 처리할 수 있습니다.
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
perror("파일 열기 실패"); // 오류 메시지 출력
return 1;
}
- ferror 함수: 파일 작업 중 오류가 발생했는지 확인하려면
ferror
함수를 사용할 수 있습니다. 이 함수는 파일 스트림에 오류가 있으면 0이 아닌 값을 반환합니다.
if (ferror(file)) {
perror("파일 작업 중 오류");
fclose(file);
return 1;
}
- feof 함수: 파일 끝에 도달했는지 확인하려면
feof
함수를 사용합니다. 파일을 끝까지 읽으면feof
가true
를 반환합니다.
if (feof(file)) {
printf("파일 끝에 도달했습니다.\n");
}
예시 코드
다음은 파일을 열고 데이터를 쓴 후, 오류를 처리하고 파일을 닫는 예시입니다:
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file == NULL) {
perror("파일 열기 실패");
return 1;
}
if (fputs("Hello, File!\n", file) == EOF) {
perror("파일 쓰기 실패");
fclose(file);
return 1;
}
if (fclose(file) != 0) {
perror("파일 닫기 실패");
return 1;
}
return 0;
}
이 코드는 파일 열기, 쓰기, 닫기 작업을 수행하고, 오류가 발생할 경우 적절한 오류 메시지를 출력합니다.
시간 기록을 위한 활용
C언어에서 프로그램의 실행 시간을 측정하거나 시간을 기록하는 데는 <time.h>
라이브러리를 사용합니다. 이 라이브러리는 다양한 시간 관련 함수들을 제공하며, 성능 측정 및 시간 관련 작업에 매우 유용합니다.
time.h 라이브러리 소개
<time.h>
는 시간 처리와 관련된 여러 가지 기능을 제공합니다. 가장 일반적으로 사용되는 함수는 time()
과 clock()
입니다. 이 함수들은 프로그램 실행 시간 측정에 주로 사용됩니다.
time() 함수
time()
함수는 현재 시간을 초 단위로 반환합니다. 이 함수는 프로그램의 시작부터 경과된 시간을 측정하거나, 현재 시간을 얻는 데 사용됩니다.
구문은 다음과 같습니다:
time_t time(time_t *t);
t
: 현재 시간을 저장할 변수에 대한 포인터입니다.t
가NULL
이면 함수는 경과된 시간을 초 단위로 반환합니다.- 반환값: 경과된 시간 또는 현재 시간.
clock() 함수
clock()
함수는 프로그램 실행 시간을 측정하는 데 사용됩니다. 이 함수는 프로그램 시작 시부터 경과된 시간을 ‘클록 틱’ 단위로 반환합니다. 이를 통해 프로그램의 실행 시간을 정밀하게 측정할 수 있습니다.
구문은 다음과 같습니다:
clock_t clock(void);
- 반환값: 프로그램 시작 후 경과된 시간(클록 틱 수).
clock()
은 시스템의 시간 단위(클록 틱)에 따라 경과 시간을 반환하므로, 이를 CLOCKS_PER_SEC
상수로 나누어 초 단위로 변환할 수 있습니다.
예시 코드
다음은 time()
과 clock()
을 사용하여 프로그램 실행 시간을 측정하는 예시입니다.
#include <stdio.h>
#include <time.h>
int main() {
time_t start_time, end_time;
time(&start_time); // 시작 시간 기록
// 프로그램에서 실행할 코드
for (int i = 0; i < 1000000; i++) {
// 반복 작업
}
time(&end_time); // 종료 시간 기록
printf("프로그램 실행 시간: %ld 초\n", end_time - start_time); // 실행 시간 출력
clock_t start_clock = clock(); // 클록 시간 시작
// 코드 실행
clock_t end_clock = clock(); // 클록 시간 종료
printf("프로그램 실행 시간(클록): %.6f 초\n", (double)(end_clock - start_clock) / CLOCKS_PER_SEC); // 실행 시간 출력
return 0;
}
이 코드는 time()
함수를 사용하여 프로그램의 경과 시간을 초 단위로 측정하고, clock()
을 사용하여 클록 틱을 기준으로 시간을 측정한 후 출력합니다.
실행 시간 측정 예시
time.h
라이브러리의 clock()
함수를 사용하여 프로그램의 실행 시간을 측정할 수 있습니다. 이 방법은 코드가 실행되는 동안 얼마나 시간이 걸렸는지에 대한 정밀한 정보를 제공합니다. 특히 성능 분석이나 최적화를 위한 중요한 도구입니다.
clock() 함수로 프로그램 실행 시간 측정
clock()
함수는 프로그램이 시작된 시점부터 경과된 시간을 ‘클록 틱’ 단위로 반환합니다. 이 값은 시스템에 따라 다를 수 있으며, 일반적으로 CLOCKS_PER_SEC
상수를 이용해 초 단위로 변환할 수 있습니다.
예시 코드
다음은 clock()
을 사용하여 특정 코드 블록의 실행 시간을 측정하는 예시입니다. 이 예시에서는 반복문을 실행하여 시간 측정을 합니다.
#include <stdio.h>
#include <time.h>
int main() {
clock_t start_time, end_time;
double time_taken;
start_time = clock(); // 시작 시간 기록
// 실행할 코드 블록 (예: 반복문)
for (int i = 0; i < 1000000; i++) {
// 일부 작업 수행
}
end_time = clock(); // 종료 시간 기록
// 경과 시간 계산 (초 단위로 변환)
time_taken = ((double)(end_time - start_time)) / CLOCKS_PER_SEC;
printf("코드 실행 시간: %f 초\n", time_taken);
return 0;
}
결과 해석
start_time
과end_time
변수는clock()
함수로 얻은 클록 틱 값을 저장합니다.CLOCKS_PER_SEC
는 시스템에서 클록 틱을 초로 변환할 때 사용하는 상수입니다.(end_time - start_time)
을CLOCKS_PER_SEC
로 나누어 실제 실행 시간을 초 단위로 계산합니다.
위 예시는 코드 블록이 실행되는 동안 소요된 시간을 측정하여 출력합니다. 이 방법은 코드 최적화 및 성능 분석에 매우 유용합니다.
성능 측정을 위한 고급 기술
C언어에서 더 정확한 성능 측정을 위해 clock()
외에도 gettimeofday()
와 clock_gettime()
함수들을 사용할 수 있습니다. 이 함수들은 더 높은 정밀도의 시간 측정을 지원하며, 특히 시스템 성능 분석에 유용합니다.
gettimeofday() 함수
gettimeofday()
함수는 현재 시간을 초와 마이크로초 단위로 반환하는 함수로, 고해상도 시간 측정을 위해 사용됩니다. 이 함수는 주로 Unix/Linux 환경에서 사용됩니다.
구문은 다음과 같습니다:
int gettimeofday(struct timeval *tv, struct timezone *tz);
tv
: 시간 정보를 저장할timeval
구조체의 포인터입니다.timeval
구조체는 초(tv_sec
)와 마이크로초(tv_usec
) 값을 가집니다.tz
: 시간대 정보(현재는 거의 사용되지 않음, 보통NULL
을 전달합니다).
gettimeofday()
는 정확한 시간 측정이 가능하고, 시스템 시간이 아니라 실제 경과된 시간을 측정하는 데 유용합니다.
clock_gettime() 함수
clock_gettime()
함수는 매우 높은 정밀도의 시간 측정을 제공합니다. CLOCK_REALTIME
이나 CLOCK_MONOTONIC
등의 다양한 시계를 사용할 수 있어, 시스템 시간이 아닌 실제 경과 시간을 측정하는 데 유용합니다.
구문은 다음과 같습니다:
int clock_gettime(clockid_t clk_id, struct timespec *tp);
clk_id
: 사용할 시계를 지정하는 값입니다.CLOCK_REALTIME
(시스템 시간) 또는CLOCK_MONOTONIC
(시스템 부팅 이후 경과 시간) 등을 사용할 수 있습니다.tp
: 결과 시간을 저장할timespec
구조체의 포인터입니다. 이 구조체는 초(tv_sec
)와 나노초(tv_nsec
) 값을 가집니다.
clock_gettime()
은 매우 높은 정밀도를 요구하는 성능 측정에서 특히 유용합니다.
예시 코드
다음은 gettimeofday()
와 clock_gettime()
을 사용하여 시간 측정을 하는 예시입니다.
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
int main() {
struct timeval start, end;
struct timespec start_time, end_time;
double elapsed_time;
// gettimeofday를 사용한 측정
gettimeofday(&start, NULL); // 시작 시간 기록
// 실행할 코드 블록 (예: 반복문)
for (int i = 0; i < 1000000; i++) {
// 일부 작업 수행
}
gettimeofday(&end, NULL); // 종료 시간 기록
elapsed_time = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000000.0;
printf("gettimeofday로 측정된 실행 시간: %f 초\n", elapsed_time);
// clock_gettime을 사용한 측정
clock_gettime(CLOCK_MONOTONIC, &start_time); // 시작 시간 기록
// 실행할 코드 블록 (예: 반복문)
for (int i = 0; i < 1000000; i++) {
// 일부 작업 수행
}
clock_gettime(CLOCK_MONOTONIC, &end_time); // 종료 시간 기록
elapsed_time = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec - start_time.tv_nsec) / 1000000000.0;
printf("clock_gettime으로 측정된 실행 시간: %f 초\n", elapsed_time);
return 0;
}
결과 해석
gettimeofday()
는 마이크로초 단위로 경과 시간을 측정할 수 있어, 짧은 시간의 성능 측정에 적합합니다.clock_gettime()
은 나노초 단위의 정밀도를 제공하므로, 높은 정확도가 요구되는 성능 측정에 더 적합합니다.
이 두 방법은 프로그램의 성능을 정확하게 측정하고 분석하는 데 매우 유용하며, 특히 짧은 시간 동안 반복적인 작업을 테스트할 때 효과적입니다.
요약
본 기사에서는 C언어에서 파일 입출력과 시간 기록 기능을 추가하는 방법을 다루었습니다. fopen
, fputs
, fread
와 같은 파일 입출력 함수들을 통해 파일 작업을 수행하고, time.h
라이브러리와 clock()
, gettimeofday()
, clock_gettime()
함수를 활용하여 프로그램의 실행 시간을 측정하는 방법을 설명했습니다. 이를 통해 C언어에서 효율적인 데이터 관리와 성능 측정을 위한 기초적인 기술을 익힐 수 있었습니다.