'IT/C 언어'에 해당되는 글 7건

#if, #else, #endif에서 주의해야할점!

IT/C 언어




몇일전 코드를 수정하다가, 아래와 같은 C언어 문법을 사용해야했다.

조건에 따라 컴파일을 포함시킬지 않알지 정하는 문법.


#if

~~

#else

~~

#endif



그러나 수정코드를 삽입하였지만, 원하는 결과는 볼 수 없었다.

조건문과 로직에는 이상이 없었다.


그렇게 한참을 디버그.. 뻘짓 하다가 뒤늦게 깨달았다.


결론, 기본적으로 빠트린 것이 있었는데.. 

#if문에서 #defined되어 있지 않은 변수명을 사용해도 소용이 없다.

이게 가장 중요한 부분인데 예를들어 보도록 하자.


예를 들어, 


op_val = 1;

#if op_val

~~~~

#else

~~~~

#endif


해서 항상 false로 인식해 #if문 아래 코드를 수행할 수 없다.


이쯤되면 이미 알아차리는 분들도 계실 수 있고, 아직 눈치채지 못하신 분들이 있으실 수 있다.


바로 컴파일 순서가 답이다. 위와 같은 예제는 항상 false로 갈 수밖에 없는데,

전처리기 컴파일 순서는 전역변수와  #defined을 먼저 컴파일하게 되어있다.


#if의 조건을 보면, op_val이란 변수는 매크로함수나 defined으로 정의되어 있지 않다.

그렇기 때문에  #if문은 항상 false를 가지며 참일때 코드로 분기할 수 없게 되는 것이다.

그렇기 때문에, op_val=1이라는 코드는 아직 컴파일 되지 않아 값이 없는 변수가 된다.


참 간단한 것이지만, 아직 기본적인것이 헤깔리거나 몰라서 이렇게 헤메는 경우가 허다한것 같다.

하나씩 기록해나가면서, 깨우쳐보도록 하자.






IPC, 공유메모리 생성 함수 shmget()

IT/C 언어

함수 원형 int shmget(ket_t key, size_t size, int shmflg);


■헤더파일

#include <sys/ipc.h>

#include <sys/shm.h>


shmget함수는 인자의 키값을 갖는 공유메모리의 식별자를 리턴한다. 

새로 생성된 공유메모리는 입력된 사이즈와 같은 크기의 공유메로리를 생성하게 된다. 


shmget()함수 인자

shmget함수는는 3개의 변수를 인자로 가진다. 

  1. ket_t key는 생성하고자 하는 공유메모리의 key값으로 key_t형이며 정수로 입력할 수 있다. 그리고 IPC_PRIVATE로 인자로 가질 경우 프로세스의 개인적인 공유메모리를 생성한다.
  2. size_t size는 생성하고자 하는 공유메모리의 크기이다.
  3. int shmflg는 공유메모리의 flg값으로 이 공유메모리의 권한과 생성시 옵션을 줄 수가 있다.IPC_CREAT와 숫자 권한을 or연산으로 입력 받는 경우가 대다수이며, IPC_CREAT옵션을 줄 경우 없다면 입력된 키값의 공유메모리가 있다면 새로성성하지않고 참조하며, 없다면 입력된 권한으로 새로 생성한다. 그와 반대로 IPC_EXCL 인자로 줄경우 이미 생성된 공유메모리가 있다면 함수를 실패하고 error를 반환한다.


■ 리턴값

함수가 성공시 공유메모리의 식별자를 반환하며, 실패시 -1을 리턴하고 errno를 셋팅한다.


■사용예제

공유메모리를 만드는 간단한 예제를 살펴보도록 하겠다.


임의적으로 key값을 주고 256의 크기를 갖는 공유메모리를 생성하는 코드를 작성했다.

만약 성공시 공유메모리 id 값을 찍을 것이고, 실패시 실패 매세지를 출력할 것이다.


컴파일하고 프로그램을 실행시켰다.


결과는,

shmid : 61538306을 갖는 공유메모리가 생성 되었다.

공유메모리가 생성 되었는지는 터미널에서 ipcs 혹은 ipcs -m을 입력시 볼 수 있다.


위 사진을 보면 shmid 61538306이고 256bytes를 갖는 공유메모리가 생성 되었음을 볼 수 있다.


좀 더 자세한 사항은

$man shmget 시에 살펴 볼 수 있다.



IPC, 메세지 큐 생성 msgget() 함수

IT/C 언어

함수원형 int msgget(key_t ket, int msgflg)


헤더파일.

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/mgs.h>


msgget 함수key 인자 값에 연관된 메세지 큐 식별자를 반환한다. 

key의 인자로 특수한 경우로 IPC_PRIVATE를 인자로 넘겨 줄 수 있는데, 이 같은 경우는 프로세스의 개인적은 큐를 생성하고 프로세스만 이용 할 수 있도록 하는 경우이다. 


msgflg의 인자는 9개의 권한을 셋팅하는 것인데 IPC_CREAT와 해당 권한을 OR 연산으로 넘겨 줄 수 있다. IPC_CREAT를 인자로 넘겨 줄 경우 이미 메세지큐가 생성되어 있다면 무시한다. IPC_EXCL는 이미 생성된 큐가 있을 시 -1을 리턴하고 ,errno 변수에 값을 세팅한다. 

IPC_CREAT와 IPC_EXCL과 권한은 전부 OR연산으로 인자에 입력 할 수가 있다.


리턴 값

성공시 메세지 큐의 식별자 값이 반환되고, 그외 경우 -1을 반환하며 errno에 해당 에러 값이 셋팅된다.


간단한 사용 예를 살펴보자.

생성된 큐는 명령어 

$ipcs -q 시 생성된 메세지 큐 list를 볼 수 있다.


자세한 사항은 

$man msgget 시 살펴 볼 수 있다.


C언어 - 파일 정보 struct stat, 구조체

IT/C 언어

파일 정보를 저장하는 구조체


struct stat 구조체를 살펴 보면 다음과 같다.


struct stat {
     dev_t           st_dev;        /*ID of device containing file */

     ino_t            st_ino;          /*inode number*/

     mode_t       st_mode;     /*protection*/

     nlink_t         st_nlink;       /*number of hard links*/

     uid_t            st_uid;          /*user ID of owner*/

     gid_t            st_gid;          /*group ID of owner*/

     dev_t           st_rdev;        /*device ID (if special file)*/

     off_t             st_size;         /*total size, in byte*/

     blksize_t      st_blksize;    /*blocksize for file system I/O*/

     blkcnt_t       st_blocks;     /*number of 512B blocks allocated*/

     time_t;        st_atime;      /*time of last access*/

     time_t;        st_mtime;     /*time of last modification*/

     time_t         st_xtime;       /*time of last status change*/

};


파일 정보를 담는 stat구조체에서 각 필드들은 각각 의미가 있다.


  • st_dev         - 장치 파일의 위치 및 여부를 기술

  • st_ino          - 파일의 inode 번호

  • st_mode     - 파일의 모드를 다룸

  • st_nlink       - 파일의 하드링크 수

  • st_uid          - user ID 

  • st_gid          - group ID

  • st_rdev        - 장치 파일 (inode)를 기술

  • st_size         - 파일의 사이즈 

  • st_blksiez   - 효율적인 I/O 파일 시스템 위한 블럭 사이즈

  • st_blocks    - 파일에 할당한 블럭의 수


stat 구조체에서 각 필드들 주목할 만한 부분은 바로 3번째 필드인 st_mode이다.


st_mode에 따라서 파일의 종류를 알 수 있고, 파일의 퍼미션(permission)도 알 수 있다.



st_mode로 파일 종류를 알 수 있는데, 위의 매크로로 설정 되어 있는 (m)부분에 st_mode 값를 넣어 주기만 하면 된다.


아래 예를 들자면,


이런 형식으로 파일 종류를 알 수 있다.


매크로를 통해 알 수 있는 방법과, 비트 연산 ( |, & )을 통해 파일 종류 및 퍼미션 등을 알 수 있다.


예를 보면,


st_mode와 간단한 비트 연산을 통해서 파일에 대한 정보들을 알 수 있다.


상세한 정보는

#man stat 명령어 시 확인 할 수 있다.


C언어 - 파일 정보 읽기 함수 stat() ,lstat() ,fstat();

IT/C 언어

함수 원형 int stat(const char *path, struct stat * buf);

함수 원형 int lstat(const char *path, struct stat * buf);

함수 원형 int fstat(int fd, struct stat * buf);


stat, lstat, fstat 함수들은 모두 파일 정보를 읽어오는 함수이다.

모두 인트형 정수를 반환하며, fstat함수는 구조체 포인터 buf와 인수형 정수 fd를 인자로 받으며,

stat와 lstat 함수는 문자열 포인터, 구조체 포인터 buf를 인자로 받는다.


각 함수들의 두번째 인자 struct stat를 살펴보면

struct stat {
     dev_t           st_dev;        /*ID of device containing file */

     ino_t            st_ino;          /*inode number*/

     mode_t       st_mode;     /*protection*/

     nlink_t         st_nlink;       /*number of hard links*/

     uid_t            st_uid;          /*user ID of owner*/

     gid_t            st_gid;          /*group ID of owner*/

     dev_t           st_rdev;        /*device ID (if special file)*/

     off_t             st_size;         /*total size, in byte*/

     blksize_t      st_blksize;    /*blocksize for file system I/O*/

     blkcnt_t       st_blocks;     /*number of 512B blocks allocated*/

     time_t;        st_atime;      /*time of last access*/

     time_t;        st_mtime;     /*time of last modification*/

     time_t         st_xtime;       /*time of last status change*/

};

위와 같은 파일 정보들을 담은 구조체 임을 알 수 있다.


위 함수들은 헤더를 선언해 줘야 사용 할 수있는데, 헤더는 다음과 같다.

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>


반환값

-각 함수들의 호출 성공시 0을 반환하며 두번째 인자인 stat 구조체에 파일 정보들로 채워진다.

실패 혹은 에러시 -1을 리턴하고 에러시에 errno 변수에 에러 상태가 set된다.


사용법

함수 각 함수들의 사용법은,


stat과 lstat함수는 첫번째 인자로, 절대경로를 넘겨주어야 하고, 두번째 인자로 stat구조체 주소를 넘겨 주어야 한다.

위와 같이 ""를 사용하여 절대경로를 주어도 되고 문자열을 만들어 주소를 넘겨주어도 된다.


stat, lstat, fstat 함수는 모두 stat함수처럼 파일의 정보를 stat구조체에 채우는 것으로 동일하지만,

lstat함수는 stat와 다르게 한가지 경우를 제외한다.


lstat함수는 path가 심볼릭 링크 파일 경우, 심볼릭 링크 파일에 대한 정보를 구조제체 채운다.

(stat함수는  원본의 정보를 채운다.)


fstat함수는 stat, lstat와 첫 번째 인자가 다른데,

fstat함수는 첫번째 인자로 파일 디스크립터 번호를 인자로 받고 stat와 동일한 기능을 수행한다.

(여기서 파일 디스크립터 번호란, fileopen 등과 같이 open함수를 호출하면 생기는 번호이다.


자세한 사항은 

$man stat, $man lstat, $man fstat 세 가지 명령어 중 1가지를 통해 볼 수있다.


C언어 - 디렉토리 읽기 함수 readdir();

IT/C 언어


함수 원형 struct dirent * readdir(DIR * dirp);


디렉토리 포인터를 인자로 받고, 디렉토리의 정보를 읽어와 dirent라는 구조체에 값을 저장 후,

dirent 구조체 포인터를 반환한다.


struct dirent를 살펴보자.

struct dirent {

               ino_t                 d_ino;              /* inode number */

               off_t                 d_off;              /* offset to the next dirent */

               unsigned short  d_reclen;         /* length of this record */

               unsigned char   d_type;            /* type of file; not supported

                                                                    by all file system types */

               char                   d_name[256]; /* filename */

 };

위에서 부터 디렉토리의 아이노트 번호, 다음 dirent까지 옵셋, 레코드의 길이, 파일타입, 파일 이름이다.


Return value로,

 -디렉토리 읽기 성공시, dirent 구조체의 포인터를 반환한다. (따로 free해줄 필요가 없다)

 -디렉토리의 끝에 도달하거나 Error시에 NULL을 반환한다. (Error시에 해당 Error을 errno에 값이 저장된다)


사용 예를 보도록 하자.

readdir 함수는 읽기가 성공시 dirent라는 구조체의 포인터를 반환한다.

이 함수는 호출할 때마다 알아서 입력된 path에 정보들을 읽어온다.

따라서 입력 path의 끝에 도달하면 NULL을 반환하기 때문에, 위처럼 while 반복문에 조건문으로 사용된다.


사용 시 위의 예처럼 struct dirent * 변수를 선언해 주어야 하며,

dirent.h 헤더파일을 include 해주어야 한다.


아래 간단한 실행 예를 보자.


이처럼 파일의 끝에 도달할 때까지 입력 path의 정보를 읽어오는 것을 볼 수 있다.


$man readdir 입력 시 더 자세한 정보를 볼 수 있다.


C언어 - 디렉토리 오픈 함수 opendir();

IT/C 언어


함수 원형 DIR * opendir(const char * name);


디렉토리 안의 파일 정보를 읽어오려면 먼저 FILE open처럼, 

DIR open을 해주어야 한다. 디렉토리 오픈을 해주기 위해 사용하는 함수로써,

반환값이 DIR이라는 구조체 포인터이고, 상수 char 포인터 를 인자로 받는다. 즉 문자열을 입력 받고

데이터 손상을 막기 위해 const로 받는다.


opendir 함수를 사용하기 위해선 dirent.h 헤더파일을 #include 해주어야 한다.

ex)

#include <dirent.h>


DIR * 변수를 선언해야 한다.

ex) DIR * spDir;


사진 예제)


예제처럼 절대path를 넣어도 되고, 변수를 넣어도 된다.


$gcc test.c 후 실행사진 )


성공했기 떄문에 success를 출력되었다.


opendir은 실패 혹은 error시에 NULL을 반환하며 error시에는 errno 값에 해당 에러 값이 set된다.


 ERRORS 종류

    -EACCES, 권한 없음.

    -EMFILE, 프로세스가 사용중인 많은 파일 디스크립터.

    -ENFILE, 시스템에서 현재 많은 파일이 오픈됨.

    -ENOENT, 디렉토리가가 없거나 문자열이 비어있음.

    -ENOMEM,  작업을 완료할 메모리가 부족함.

    -ENOTDIR,  디텍토리 파일이 아님. 


좀 더 자세한 정보는 

$man opendir 명령시 확인 할 수 있다.