사용자 관련 정보 검색함수 getutxent()에 대해서
오늘 우연히 사용하게 되어 이에 대한 기록을 남겨놓고 감.

utmp => who 명령어에서 사용함.

wtmp => last 명령어에서 사용함

 

함수를 사용할때 추가해야할 해더파일

#include <utmpx.h>

   

getutxent함수와 관련된 다른 함수들

struct utmpx *getutxent(void);

void setutxent(void);

void endutxent(void);

int utmpxname(const char *file);     => file - 교체할 파일이름이 매개변수로 넘어간다. 

   

 getutxent 함수는 /var/adm/utmpx 파일에서 로그인 정보를 순차적으로 읽어들임.

 setutxent 함수는 /var/adm/utmpx 파일의 오프셋을 파일의 시작에 위치시킴.

 endutxent 함수는 /var/adm/utmpx 위에서 열었던 파일을 닫는다.

 utmpxname 함수는 로그인 정보 파일을 file로 지정한 다른 파일로 변경.

   

해당 정보가 있는 파일의 경로 (각 OS별)

로그파일

Solaris

HP UX

LINUX

wtmp,utmp

/var/adm/wtmpx

/var/adm/utmpx

/usr/adm/wtmp

/etc/utmp

/var/log/wtmp

/var/run/utmp

   

====================================

 

#include "sys/types.h"
#include 
#include 

int main(void) {

    struct utmpx *utx;

    printf("-----------------\n");
    printf("   Login User\n");
    printf("-----------------\n");

    while((utx=getutxent()) != NULL) {
        if(utx->ut_type != USER_PROCESS)
            continue;

        printf("%10s %5s\n", utx->ut_user, utx->ut_line);
    }

    return 0;

}
결과화면
$ ./a.out 
-----------------
   Login User
-----------------
  telcosys  tty1
     fresh pts/4
      jeon pts/3

* who 명령의 결과화면
$ who
telcosys tty1         May 17 09:08
fresh    pts/4        Aug 13 14:34 (10.10.101.55)
jeon     pts/3        Aug 13 19:57 (10.10.104.55)

====================================   

   

utmp파일에는 현재 접속중(Telnet ..) 사용자의 정보가 저장되는데,

로그아웃을 하면 이에 대한 정보가 삭제됨.

   

wtmp파일은 로그인시 utmp파일에 쓰이는 것과 같은 정보가 쓰여지고,

사용자가 로그아웃을 하면 정보도 쓰여지게 됨.(updwtmp).

또한 컴퓨터의 리부팅과, 몇몇정보들이 추가로 쓰여짐.

   

 

원본 source 파일을 첨부해서 살펴보면 아래와 같다.

출처 : http://www2.oldlinux.org/Linux.old/Linux-0.98/Yggdrasil-0.98.3/usr/src/sbin/getty_ps/getutent.c

==========================

 

/* getutxent.c */

#include 
#include 

struct utmpx *
getutxent (void)
{
  return (struct utmpx *) __getutent ();
}
/* getutent.c */


#include "getty.h"

#if defined(RCSID) && !defined(lint)
static char *RcsId =
"@(#)$Id: getutent.c,v 2.0 90/09/19 20:00:51 paul Rel $";
#endif

typedef	struct utmp	UTMP;

static	char	*utmpfil = UTMP_FILE;	/* default utmp file */
static	FILE	*ufp = (FILE *) NULL;	/* file pointer to utmp file */
					/* NULL = no utmp file open  */
static	UTMP	ut;			/* buffer for utmp record */


/*
**	getutent() - get next valid utmp entry
**
**	Returns (UTMP*)NULL if no vaild entry found.
*/

UTMP *
getutent()
{
	if (ufp == (FILE *) NULL)
		if ((ufp = fopen(utmpfil, "r+")) == (FILE *) NULL)
			return((UTMP *) NULL);

	do {
		if (fread((char *)&ut, sizeof(ut), 1, ufp) != 1)
			return((UTMP *) NULL);

	} while (ut.ut_name[0] == '\0');	/* valid entry? */

	return(&ut);
}


/*
**	getutline() - get utmp entry that matches line.
**
**	Returns (UTMP*)NULL if no match found.
*/

UTMP *
getutline(line)
register UTMP *line;
{
	do {
		if (strequal(ut.ut_line, line->ut_line))
			return(&ut);	/* match! */

	} while (getutent() != NULL);

	return((UTMP *) NULL);
}


/*
**	setutent() - rewind utmp back to beginning
*/

void
setutent()
{
	if (ufp != (FILE *) NULL)
		rewind(ufp);
}

/*
**	endutent() - close utmp file
*/

void
endutent()
{
	if (ufp != (FILE *) NULL) {
		(void) fclose(ufp);
		ufp = (FILE *) NULL;
	}
}

/*
**	utmpname() - change utmp file name to "file"
*/

void
utmpname(file)
register char *file;
{
	endutent();
	utmpfil = strdup(file);
}

/* end of getutent.c */

==========================

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

strchr 함수 예제  (0) 2012.08.14
strdup 함수 예제  (0) 2012.08.14
getutxent 함수 예제  (0) 2012.08.13
strtok 함수 예제  (0) 2012.08.06
writev 함수 예제  (0) 2012.07.31
readv 함수 예제  (0) 2012.07.30

이름
       strtok, strtok_r - 문자열에서 토큰들을 뽑아낸다.

사용법
       #include <string.h>

       char *strtok(char *s, const char *delim);

       char *strtok_r(char *s, const char *delim, char **ptrptr);

 

예제를 보면 아래처럼 쉽게 테스트할 수 있다.

==============================

 

#include 
#include 
#include 

int main()
{
    char *temp = "/home/test/HISTORY/history/test_file";
    char *aa, buf[256];

    strncpy(buf, temp, sizeof(buf));

    printf("before strtok : %s\n", buf);
    aa = strtok(buf, "/");
    printf("after strtok :%s\n", buf);
    printf("result : %s\n", aa);

    return 0;
}

==============================

위의 함수를 실행한 결과는 아래처럼 나온다.

$ ./a.out
before strtok : /home/test/HISTORY/history/test_file
after strtok :/home
result : home

 

딜리미터로 슬래쉬 '/'를 썼는데

슬래쉬가 2번째 나타나는 부분 이전까지 잘리는 것을 볼 수 있다.

그리고 return 하는 char 포인터는

첫번째 '/'의 다음을 가리키고 있다.

 

 

 

strtok 함수의 실제 코드를 뜯어보면 아래와 같다.

출처 : http://opensource.apple.com/source/Libc/Libc-167/string.subproj/strtok.c

======================================

 

#include 
#include 

char *
strtok(s, delim)
	register char *s;
	register const char *delim;
{
	register char *spanp;
	register int c, sc;
	char *tok;
	static char *last;


	if (s == NULL && (s = last) == NULL)
		return (NULL);

	/*
	 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
	 */
cont:
	c = *s++;
	for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
		if (c == sc)
			goto cont;
	}

	if (c == 0) {		/* no non-delimiter characters */
		last = NULL;
		return (NULL);
	}
	tok = s - 1;

	/*
	 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
	 * Note that delim must have one NUL; we stop if we see that, too.
	 */
	for (;;) {
		c = *s++;
		spanp = (char *)delim;
		do {
			if ((sc = *spanp++) == c) {
				if (c == 0)
					s = NULL;
				else
					s[-1] = 0;
				last = s;
				return (tok);
			}
		} while (sc != 0);
	}
	/* NOTREACHED */
}

 

======================================

 

 

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

strdup 함수 예제  (0) 2012.08.14
getutxent 함수 예제  (0) 2012.08.13
strtok 함수 예제  (0) 2012.08.06
writev 함수 예제  (0) 2012.07.31
readv 함수 예제  (0) 2012.07.30
poll 함수 예제  (0) 2012.07.26

NAME
       readv, writev - read or write data into multiple buffers

SYNOPSIS
       #include <sys/uio.h>

       ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

소스코드 출처 : http://www.ccplusplus.com/2012/02/writev-example-linux.html

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

 

#include 
#include 
#include 
#include 
#include 
#include "sys/uio.h"

int main(int argc,char **argv) {
    static char part2[] = "THIS IS FROM WRITEV : http://www.ccplusplus.com/";
    static char part3[] = "]\n";
    static char part1[] = "[";
    struct iovec iov[3];

    iov[0].iov_base = part1;
    iov[0].iov_len = strlen(part1);

    iov[1].iov_base = part2;
    iov[1].iov_len = strlen(part2);

    iov[2].iov_base = part3;
    iov[2].iov_len = strlen(part3);

    writev(1,iov,3);

    return 0;
}
수행결과 화면

$ ./a.out 

[THIS IS FROM WRITEV : http://www.ccplusplus.com/]

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

내용 출처 : http://blog.naver.com/playboy999/140117532970

writev 함수는 여러 개의 packet을 쪼게 거나 또는 나누어서 송, 수신한다.

즉 함수의 호출 횟수가 줄어든다. 그러면 성능상의 효율성이 높아진다.

일반적으로 함수의 호출이 일어날 경우 각각의 호출이 stack에 저장되고 함수의 실행이 끝나면 stack에서 pop이 된다. 그럼으로 이러한 stack의 사용의 횟수가 적어짐으로 이점이 발생한다.
그러나 이 부분 보다 전송되는 packet의 수를 줄일 수 있다는 것이 더 큰 이유가 된다.

예를 들어 Nagle algorithm이 off 일 경우를 생각해 보자.

  

   

Nagle algorithm이 off 인 경우 출력 buffer에 data가 들어오자 마자 data를 블록화 하여 전송하기 때문에 각각의 data가 packet화 하여 전송된다. 한번에 블록화 하여 전송할 수 있는 data를 여러 개의 packet으로 나누어 전송한 상황이 된다. 이러한 전송은 전송되는 packet이 적을 경우 문제가 되지 않지만 packet이 많아질 경우 전체 network에 영향을 끼치게 된다.

같은 양의 data를 전송하더라도 여러 packet으로 나누어 전송하면 각각의 packet에 header의 수가 증가함으로 network 입장에서는 traffic의 증가와 수신하는 호스트 입장에서는 처리해야 하는 packet의 수가 증가하는 꼴이 된다.

이러한 경우에 기존의 write함수보다 writev함수를 사용하면 높은 buffer에 저장되어 있는 data를 하나로 블록화하여 전송할 수 있다.

 

 

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

getutxent 함수 예제  (0) 2012.08.13
strtok 함수 예제  (0) 2012.08.06
writev 함수 예제  (0) 2012.07.31
readv 함수 예제  (0) 2012.07.30
poll 함수 예제  (0) 2012.07.26
GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24

read 함수와 매우 동일한 함수다. 

다만 다중 버퍼를 사용할 수 있다는 것만 차이점이다. 


NAME

       readv, writev - read or write data into multiple buffers


SYNOPSIS

       #include <sys/uio.h>


       ssize_t readv(int fd, const struct iovec *iov, int iovcnt);



리턴값 : 성공시 전송한 바이트 수, 실패시 -1 리턴

인자값 :

 - fd : 데이터 전송의 목적지를 나타내는 소켓의 파일 디스크립터를 전달한다.

        반드시 소켓에만 제한되는 함수가 아니다. read, write 함수처럼 파일이나

         콘솔을 입, 출력 대상으로 할 수도 있다.

 - vector : 일반적으로 iovec 구조체 배열의 이름을 인자로 전달하는데, iovec 구조체에는

               전송하고자 하는 데이터에 대한 정보가 담겨진다.

 - count : 데이터를 전송하기 위해 참고할 iovec 구조체 변수의 수를 지정한다. 만약에 3이 인자로
              전달되면, vector가 가리키는 iovec 구조체 변수를 시작으로 총 3개의 iovec 변수를 참고하여

               데이터를 전송하게 된다.



iovec (I/O vector)의 구조체는 /etc/include/sys/uio.h 에 선언되어있다.

       

           struct iovec {

               void  *iov_base;    /* Starting address */

               size_t iov_len;     /* Number of bytes to transfer */

           }

 

 

 


 

간략한 예제는 다음과 같다.

=====================================



#include 
#include 
#include 
#include 
#include 

int main ()
{
    char foo[48], bar[51], baz[49];
    struct iovec iov[3];
    ssize_t nr;
    int fd, i;

    fd = open ("test.txt", O_RDONLY);
    if (fd == -1) {
        perror ("open");
        return 1;
    }

    /* set up our iovec structures */
    iov[0].iov_base = foo;
    iov[0].iov_len = sizeof (foo);
    iov[1].iov_base = bar;
    iov[1].iov_len = sizeof (bar);
    iov[2].iov_base = baz;
    iov[2].iov_len = sizeof (baz);

    /* read into the structures with a single call */
    nr = readv (fd, iov, 3);
    if (nr == -1) {
        perror ("readv");
        return 1;
    }

    for (i = 0; i < 3; i++)
        printf ("%d ==>> %s\n", i, (char *) iov[i].iov_base);

    if (close (fd)) {
        perror ("close");
        return 1;
    }

    return 0;
}
시험결과는 다음과 같다.
$ ./a.out 
0 ==>> LONDON ? The swimmer Dana Vollmer is an unabashe?
1 ==>> d fan of the gymnasts Shannon Miller and Nastia LiuLONDON ? The swimmer Dana Vollmer is an unabashe?
2 ==>> kin, which makes sense. Miller and Liukin won Olyd fan of the gymnasts Shannon Miller and Nastia LiuLONDON ? The swimmer Dana Vollmer is an unabashe?

=====================================

3개의 버퍼를 선언하는데 48, 51, 49 byte로 각기 다른 사이즈로 했다.

1번째 줄은 49 byte 출력

2번째 줄은 100byte 출력

3번째 줄은 149byte 출력


버퍼보다 사이즈가 하나 더 늘어나서 출력되는 것 같은데

마지막에 ? (물음표)가 더해졌다. 이유는 아직 잘 모르겠다. OTL.. 

 

 

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

strtok 함수 예제  (0) 2012.08.06
writev 함수 예제  (0) 2012.07.31
readv 함수 예제  (0) 2012.07.30
poll 함수 예제  (0) 2012.07.26
GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24
select 함수 예제  (0) 2012.07.23

select는 특정 이벤트가 발생하면 running을 하지만 

poll은 계속해서 주기적으로 돌면서 이벤트를 체크한다. 


int poll(struct pollfd *fds, nfds_t nfds, int timeout);


1인자값 : 이벤트 등록 변수

2인자값 : 체크할 pollfd의 개수

3인자값 : time out 시간 


만약에 poll(0, 0, 1000); 이렇게 하면 

sleep(1); 과 같이 1초 delay를 줄 수 있다. 


출처: http://forum.falinux.com/zbxe/?document_srl=405838

위의 페이지에 따르면


POLL함수는 확인하고 싶은 여러가지 이벤트를 미리 등록해놓고 그 이벤트들이 발생했는지

확인할 수 있는 편리한 방법을 제공한다.

POLL 함수의 PHASE는 5단계로 다음과 같다. 


PHASE 1 : 주기적으로  check할 이벤트 등록

PHASE 2 : poll() 함수를 호출한다. 

PHASE 3 : 이벤트가 발생하면 poll()함수 호출 후에 바로 return.

PHASE 4 : 이벤트가 발생하지 않으면, 이벤트 발생할 때까지 time-out 시간 만큼 기다린다. 

PHASE 5 : 이벤트가 발생하면 해당 이벤트 배열 아이템의 값이 바뀌는데 이 값을 가지고 어느 이벤트가 발생했는지 알 수 있다. 


< 서버쪽 예제> ... 클라이언트가 자꾸 제대로 안된다.. OTL..

코드출처 : http://stackoverflow.com/questions/448331/my-simple-poll-example-only-partially-works

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


#include 
#include 
#include 
#include 
#include "sys/time.h"
#include "sys/types.h"
#include 
#include 
#include "sys/socket.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include 

#define PORT 29900 
#define MAX_CONN 10
#define SECOND 1000
#define TIMEOUT (30 * SECOND)

static int listen_socket();

int main(int argc, char **argv)
{
    struct pollfd **my_fds;                  //array of pollfd structures for poll()
    struct pollfd *curr, *new_conn;          //so I can loop through
    int num_fds;                             //count of how many are being used
    int i, j;                                //for loops
    char buff[255], buff2[255];              //for sending and recieving text
    struct sockaddr_in my_addr, their_addr;  // my address information
    socklen_t sin_size;
    int buff_sz;                             //size of data recieved

    printf("App Started\n");

    //allocate space for 10 
    my_fds = (struct pollfd**)calloc( MAX_CONN, sizeof(struct pollfd*));

    //set all the pointers to NULL
    for (i = 0; i < MAX_CONN; i++)
        *(my_fds + i) = NULL;

    //I call listen_socket() which creates a socket to listen to
    //this is anchored into my_fds array at element 0.
    curr = (struct pollfd*) calloc (1, sizeof(struct pollfd));
    curr->fd = listen_socket();
    curr->events = POLLIN;
    curr->revents = 0;

    *my_fds = curr;

    printf("Listening socket fd locked always at position zero in array: %d\n", curr->fd);

    //num_fds, the count of items in the array is set to 1
    //because the listen socket is already present
    num_fds = 1;

    //This is the main loop.
    //While (true)
    //  set all struct pollfd items revents to 0
    //  call poll
   //  loop through, see if there is data to read
    //  read the data
    //  loop through all sockets (except the listen_socket()) and send the data.
    while (1)
    {
        //reset all event flag
        for (i = 1; i < num_fds; i++)
        {
            curr = *(my_fds + i);
            curr->events = POLLIN | POLLPRI;
            printf("%i: fd %i\n", i, curr->fd);
            curr->revents = 0;
            send(curr->fd, "Enter some text:\n", 18, 0);
        }

        //put all this into poll and wait for something magical to happen
        printf("calling poll (%d sockets)\n", num_fds);
        if (poll(*my_fds, num_fds, TIMEOUT) == -1)
        {
            perror("poll");
            exit(0);
        }

        printf("poll returned!\n");

        //First item is the accepting socket....check it independently of the rest!
        curr = *my_fds;
        if (curr->revents != 0)
        {
            printf("We have a new connection.\nAccept goes here...\n");

            //Accept the connection
            sin_size = sizeof their_addr;
            new_conn = (struct pollfd*) calloc(1, sizeof(struct pollfd));
            new_conn->fd = accept(curr->fd, (struct sockaddr *)&their_addr, &sin_size);
            new_conn->events = POLLIN;
            new_conn->revents = 0;

            printf("Connection from %s\n", inet_ntoa(their_addr.sin_addr));
            sprintf(buff, "Your %i\n", num_fds);
            send(new_conn->fd, buff, 255, 0);

            //Add it to the poll call
            *(my_fds + num_fds) = new_conn;
            num_fds++;

        }
        else
        {
            //skip first one, we know that's the accepting socket (handled above).
            for (i = 1; i < num_fds; i++)
            {
                curr = *(my_fds + i);
                if (curr->revents != 0)
                {
                    buff_sz = recv(curr->fd, &buff, 255, 0);
                    buff[buff_sz] = '\0';
                    printf("Recieved: %s", buff);

                    //send the message to everyone else
                    for (j = 1; j < num_fds; j++)
                    {
                        printf("i = %i, j = %i\n", i, j);
                        if (j != i)
                        {
                            new_conn = *(my_fds + j);
                            sprintf(buff2, "%i sent you %i: %s", i, j, buff);
                            send(new_conn->fd, buff2, strlen(buff2) + 1, 0);
                        }
                    }
                }
            }
        }
    }

    printf("App Ended\n");
}

static int listen_socket()
{
    struct sockaddr_in a;
    int s;
    int yes;

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        return -1;
    }
    yes = 1;
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                (char *) &yes, sizeof(yes)) < 0) {
        perror("setsockopt");
        close(s);
        return -1;
    }
    memset(&a, 0, sizeof(a));
    a.sin_port = htons(PORT);
    a.sin_family = AF_INET;
    if (bind(s, (struct sockaddr *) &a, sizeof(a)) < 0) {
        perror("bind");
        close(s);
        return -1;
    }
    printf("Accepting connections on port %d\n", PORT);
    listen(s, 10);
    return s;
}


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


도무지 이해가 안가서 일부분만 떼어왔다.

http://forum.falinux.com/zbxe/?document_srl=405838

struct pollfd poll_events; // 체크할 event 정보를 갖는 struct

poll() 사용하기 위한 변수를 선언.
poll_events
에는 감시 대상인 디스크립터와 어떤 event 감시할지 결정해서 bit 값으로 지정.

int poll_state;

poll() 수행한 결과값. 아래와 같은 반환값.

 

poll() 수행 반환

 

반환

설명

음수

반환 값이 음수라면 치명적인 에러가 발생한 것입니다. 한번 이렇게 음수로 에러가 발생하면 이후 계속 음수값이 날라 옵니다. 거의 대부분 프로그램을 다시 실행해야 됩니다. 반드시 체크해야 겠지요.

0

지정한 대기시간, time-out 지나도록 발생한 event 없습니다.

양수

event 발생했습니다.

 

poll_events.fd = fd;

감시 대상인 디스크립터를 지정.

poll_events.events = POLLIN | POLLERR; // 수신된 자료가 있는지, 에러가 있는지

체크하고 싶은 event 대해 비트값으로 설정하여 지정.

poll_events.revents = 0;

revents 0 으로 초기화.

poll_state = poll(                               // poll() 호출하여 event 발생 여부 확인    
                  (
struct pollfd*)&poll_events, // event 등록 변수
                                             1,  //
체크할 pollfd 개수
                                          1000   // time out
시간
                );

체크할 event 정보를 넘겨 주고, 1 체크할 pollfd 개수.

예제에는 감시하는 디스크립터가 개이지만 프로그램에 따라서는 여러 개의 디스크립터를 관리할 경우가 많음.

 

관리할 디스크립터가 많을 , 각각을 변수로 처리하는 보다 배열로 처리하는 것이 편리.

이래서 poll() 편리.

poll() 변수 하나 외에도 배열을 받을 있으며,

한번의 호출로 모든 event 발생 여부를 확인할 있어 매우 편리.

 

1000 time-out 시간으로 발생한 event 없을 경우

poll() event 발생할 까지 time-out 시간 동안 대기.

 

if ( 0 < poll_state)

poll() 함수 결과가 양수라면 event 발생.

if ( poll_events.revents & POLLIN)

발생한 event 중에 POLLIN 있는 지를 확인.

POLLIN 해당되는 bit 1 세트되어 있다면 POLLIN으로 AND 값은 0 아닐 .

이렇게 비트값을 확인하여 event 발생 여부를 확인.

cnt = read( fd, buf, 1024);

write( fd, buf, cnt);

자료 수신 event 발생했으므로 fd로부터 자료 값을 읽어 들이고,

예제 테스트를 위해 다시 자료를 전송.

 

 

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

writev 함수 예제  (0) 2012.07.31
readv 함수 예제  (0) 2012.07.30
poll 함수 예제  (0) 2012.07.26
GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24
select 함수 예제  (0) 2012.07.23
Unix Domain Socket 예제  (0) 2012.07.23

이 문서는 GCC Version 2.7.2를 기준으로 하여 이 컴파일러가 출력하는 에러 [error]와 경고 [warning] 메시지를 한국어로 번역하고, 그 메시지를 발생할 수 있는 간단한 예제를 보이며, 간단한 해결책을 제시합니다.

 

GCC Error (Warning) Message List

Copyright © 1999 Seong-Kook Cin

   Seong-Kook Cin Jang-Chon Dong 21-2 Sun-Chon City 540-190 South KOREA

   

Before reading this

이 문서는 GCC Version 2.7.2를 기준으로 하여 이 컴파일러가 출력하는 에러 [error]와 경고 [warning] 메시지를 한국어로 번역하고, 그 메시지를 발생할 수 있는 간단한 예제를 보이며, 간단한 해결책을 제시합니다.

이 문서는 C 배우미들이 낯선 컴파일러 메시지를 만났을 때 당황하지 않고 쉽게 문제를 해결할 수 있기를 바라는 뜻에서 만들어진 것입니다.

이 문서는 유용하게 쓰여지기를 바라면서 만들어졌지만 저자는 이 문서에 대해 어떠한 보증도 하지 않습니다. 즉, 이 문서에 의해 일어날 수 있는 손해에 대해서는 책임을 지지 않습니다.

이 문서는 GCC가 발생할 수 있는 에러 메시지를 모두 포함하지 않을 수도 있습니다. 여러분이 이 문서에 없는 에러 메시지를 발견해서, 이 문서에 추가하기를 원하거나, 이 문서에 틀린 곳을 수정하기를 원한다면

cinsk@acm.org 으로 e-mail을 보내시기 바랍니다. 어떠한 제안이나 비판도 환영합니다. 저자는 여러분들의 참여로 이 문서가 보다 완전해지기를 원합니다.

   

Conventions

영어를 한국어로 쓸 때, 한국어를 영어로 표기할 때 혼동을 가져올 수 있는 용어나 기타 부가적인 설명은 그 용어 뒤의 `[]'안에 옵니다. 문서의 형식은 다음과 같습니다.

에러 메시지

에러 메시지 설명......................

이 에러 메시지를 발생시키는 예제

   

파일:줄 번호: 실제 컴파일러가 발생하는 에러 메시지

   

Table of Contents

Errors

   

   

   

   

   

   

   

   

Warnings

   

   

   

   

   

   

   

warning: initializer-string for array of chars is too long

주어진 배열이 가질 수 있는 문자의 개수보다 많은 초기값이 주어진 경우에 발생합니다. C 언어의 문자열은 큰 따옴표(`"')로 둘러싸서 나타내며 문자열의 끝을 나타내기 위해 ASCII 코드 0번 문자(`\0')를 사용합니다. 따라서 아래의 예에서 배열 `ca'는 크기가 5로 되어 있어야 합니다.

문자열 배열을 쓸 때마다 이런 식으로 배열의 크기를 지정해 주는 것은 번거로운 일입니다. 배열이 초기값을 가지고 있을 때에는 배열의 크기를 지정하지 않아도(`ca[]') 좋습니다.

char ca[3] = "abcd";

   

file:1: warning: initializer-string for array of chars is too long

   

invalid #-line

라인 [line] 번호 정보를 잘못 입력한 경우에 발생합니다. 라인 번호는 0보다 큰 양수 [positive number]이어야 합니다.

invalid format `#line' directive 에러를 참고하시기 바랍니다.

# 0 "foo.c"

   

file:1: invalid #-line

또는,

#line 0

   

file:1: invalid #-line

   

parse error before `XXX'

이 에러가 발생하는 조건은 너무나도 많습니다. 일반적으로 문장을 분석 [parse]할 때 예상하지 못한 구문을 발견했을 경우에 이 에러가 발생합니다. parse error 에러를 참고하기 바랍니다.

조건 1: typedef로 정의한 형에 short, long, signed, unsigned 등을 사용할 때.

typedef int INT;

unsigned INT ui;

   

file:2: parse error before `ui'

file:2: warning: data definition has no type or storage class

조건 2:

void f()

{

else {

}

}

   

file: In function `f':

file:3: parse error before `else'

   

warning: `XXX' redefined

사용자가 정의한 매크로를 다시 정의하거나, ANSI C 혹은 컴파일러가 미리 정의해 놓은 매크로를 재 정의하려 할 때 발생합니다. 사용자가 정의한 매크로인 경우, #undef 지시어를 써서 이 경고를 없앨 수 있습니다.

#define MY_CONST "cinsk"

#define MY_CONST "windy"

   

file:2: warning: `MY_CONST' redefined

   

warning: undefining `XXX'

ANSI C 혹은 컴파일러가 미리 정의해 놓은 매크로(predefined macro)를 없앨 경우에 발생합니다. 이 경고가 발생할 경우, 여러분은 다른 매크로를 써야 합니다. 미리 정의된 매크로를 다른 목적으로 쓰는 것은 좋지 않습니다. ANSI C 혹은 컴파일러가 미리 정의해 놓은 상수 목록은 컴파일러와 함께 제공되는 매뉴얼을 참고하시기 바랍니다.

#undef __FILE__

   

file1: warning: undefining `__FILE__'

   

ANSI C requires a named argument before `...'

ANSI C는 하나 이상의 가변 인자 [variable length argument]를 받을 수 있게 하지만 하나 이상의 고정된 인자가 있어야 합니다. 아래의 예에서 함수 f()는 고정된 인자가 하나도 없기 때문에 이 에러가 발생합니다.

void f(...) { }

   

file:1: ANSI C requires a named argument before `...'

   

unterminated macro call

주어진 매크로의 인자를 읽을 때 괄호가 닫히지 않을 경우 이 에러가 발생합니다.

#define NOP(x)

NOP(foo

   

file:2: unterminated macro call

   

duplicate argument name `XXX' in `#define'

매크로를 정의할 때 같은 이름을 두 인자에 대해 썼을 경우 이 에러가 발생합니다.

#define ADD3(a, a, c) ((a) + (b) + (c))

   

file:1: duplicate argument name `a' in `#define'

   

parse error

어구 분석(parsing)에 실패했을 경우 이 에러가 발생합니다. 이 에러가 발생하는 경우는 매우 많습니다. parse error before `XXX' 에러를 참고하기 바랍니다.

조건 1: `#elif' 다음에 상수식이 오지 않을 때

#if defined(ONE)

int i = 1;

#elif

int i = 2;

#endif

   

file3: parse error

조건 2: 비어있는 매크로를 잘못 썼을 때.

#define EMPTY

#if EMPTY

char *msg = "EMPTY is non-empty";

#endif

   

file:2: parse error

   

empty character constant

빈 문자 상수가 쓰였을 때 이 에러가 발생합니다.

int i = '';

   

file:1: empty character constant

   

empty file name in `#include'

`#include' directive에서 파일 이름이 주어지지 않았을 때 발생합니다.

#include <>

   

file:1: empty file name in `#include'

   

unbalanced `#endif'

`#endif' directive가 if 섹션 ('#if', `#ifdef', `#ifndef' 등으로 시작하는) 과 맞게 쓰이지 않을 때 발생합니다.

#endif

   

file:1: unbalanced `#endif'

   

warning: declaration of `xxx' shadows a parameter

int f(int i)

{

enum e { l, j, k, i};

}

   

file: In function `f':

file:3: warning: declaration of `i' shadows a parameter

file:4: warning: control reaches end of non-void function

   

warning: integer overflow in expression

정수로 취급되는 식 (enumerator 포함)에서 오버플로우(overflow)가 일어날 경우에 이 경고가 발생합니다.

#include

   

enum A { AA = INT_MAX + 1 };

   

file:3: warning: integer overflow in expression

   

#error XXX

이 에러는 컴파일러에게 소스가 전달되기 전, 프리프로세서(preprocessor)에 의해 발생합니다. 프리프로세서는 `#error'로 시작하는 문장을 만나면 바로 컴파일 작업을 중단하고 `#error' 문장을 출력합니다. 이는 대개 프로그램 소스가 특별한 환경을 요구하는 경우, 적합하지 않은 환경일 때에는 컴파일이 되지 않게 하기 위한 목적으로 쓰입니다.

ANSI C에서는 몇 개의 미리 정의된(predefined) 상수를 정의하고 있고, 컴파일러에 따라서 추가적인 상수를 제공합니다. `#error'의 경우, 이들 상수와 같이 쓰이는 경우가 일반적이므로, 자세한 것은 컴파일러의 매뉴얼을 참고하시기 바랍니다.

#ifndef NEVER_DEFINED

#error NEVER_DEFINED required

#endif

file:2: #error NEVER_DEFINED required

   

parameter name omitted

int f(int)

{

return 0;

}

   

file:1: parameter name omitted

   

`XXX' declared as function returning an array

int f(void)[];

   

file:1: `f' declared as function returning an array

   

called object is not a function

void f(void)

{

char *p;

p();

}

   

file: In function `f':

file:4: called object is not a function

   

   

warning: `return' with no value, in function returning non-void

int f(void)

{

return;

}

   

file: In function `f':

file:3: warning: `return' with no value, in function returning non-void

   

file

   

unterminated character constant

문자 상수가 `''로 닫히지 않을 경우에 발생합니다.

char ch = 'a;

   

file:1: unterminated character constant

   

unterminated comment

주석 [comment]이 `/*'로 닫히지 않을 경우에 발생합니다.

/* This is a comment

   

file:1: unterminated comment

   

unterminated string or character constant

문자 상수나 문자열이 `"'로 끝나지 않을 경우에 발생합니다.

char *str = "cinsk\

the wind

   

file:1: unterminated string or character constant

file:2: possible real start of unterminated constant

   

possible real start of unterminated constant

문자 상수나 문자열이 `"'로 끝나지 않을 경우에 발생합니다.

char *str = "hello\

world

   

file:1: unterminated string or character constant

file:2: possible real start of unterminated constant

   

warning: return-type defaults to `int'

함수의 리턴 형 [return type]을 생략할 경우에 발생합니다. 리턴 형이 생략된 함수의 리턴 형은 `int'입니다.

foo(void)

{

return 0;

}

   

file:2: warning: return-type defaults to `int'

   

warning: control reaches end of non-void function

함수의 리턴 형 [return type]이 `void'가 아닌데도 함수가 `return' 문을 가지지 않을 경우에 발생합니다. 이 경우 함수를 `void' 형으로 선언하거나 `return' 문을 쓰면 해결됩니다.

int foo(void) {}

   

file:1: warning: control reaches end of non-void function

   

warning: dereferencing `void *' pointer

void 형 포인터 [pointer]는 다른 형 포인터로 캐스트 [cast]하기 전에는 쓸 수 없습니다. 즉, 이 에러는 void 형 포인터에 역참조 [dereference] 연산자인 `*'를 썼기 때문에 발생합니다. 이 에러를 해결하려면 void 형 포인터를 다른 형 포인터 (예를 들어 `int *')로 캐스팅 [casting]해서 쓰면 됩니다.

void foo(void)

{

void *p, *q;

*(p = q);

}

   

file:4: warning: dereferencing `void *' pointer

file:4: warning: value computed is not used

   

dereferencing pointer to incomplete type

정의되지 않은 형을 가리키는 포인터 [pointer]에 역참조 [dereference] 연산자(`*')를 쓸 수 없습니다.

struct s;

void g(struct s *);

void f(void)

{

struct s *p;

g(*p);

}

   

file:6: dereferencing pointer to incomplete type

   

warning: passing arg N of `XXX' makes integer from pointer without a cast

함수 XXX의 N번째 파라메터 [parameter]가 정수형인데도 캐스팅 [casting]없이 포인터를 인자 [argument]로 쓴 경우에 발생합니다.

void f(int);

void g(void)

{

f("erroneous");

}

   

file:4: warning: passing arg 1 of `f' makes integer from pointer without a cast

   

int f(char *);

void g()

{

f(5);

}

   

file: In function `g':

file:4: warning: passing arg 1 of `f' makes pointer from integer without a cast

   

   

incompatible type for argument N of `XXX'

함수 선언에 쓰인 파라메터 [parameter]의 형과 실제 인자 [argument]의 형이 서로 달라서 변경할 수 없는 경우에 발생합니다.

struct s { int a; } p;

void f(void)

{

void g(int, int);

g(5, p);

}

   

file:5: incompatible type for argument 2 of `g'

   

too few arguments to function `XXX'

함수 선언에 쓰인 파라메터 [parameter]의 수보다 실제 인자 [argument]의 개수가 적을 경우에 발생합니다.

void f(void)

{

void g(int, int);

g(5);

}

   

file:4: too few arguments to function `g'

   

too many arguments to function `XXX'

함수 선언에 쓰인 파라메터 [parameter]의 수보다 실제 인자 [argument]의 개수가 많을 경우에 발생합니다.

void f(void)

{

void g(int);

g(5, 2);

}

   

file:4: too many arguments to function `g'

   

incompatible types in assignment

대입 [assignment] 연산에서 연산자 `=' 사이의 오퍼랜드 [operand]의 형이 서로 완전히 다릅니다. assignment makes integer from pointer without a cast 경고를 참고하시기 바랍니다.

struct s {};

void f()

{

struct s st;

int i;

i = st;

}

   

file:7: incompatible types in assignment

   

warning: assignment makes integer from pointer without a cast

대입 [assignment] 연산에서 연산자 `=' 양쪽에 오는 오퍼랜드 [operand]가 왼쪽은 정수형, 오른쪽은 포인터일 경우에 이 경고가 발생합니다. 이를 해결하려면 포인터를 정수형으로 캐스팅 [casting]해야 합니다. incompatible types in assignment 에러를 참고하시기 바랍니다.

void f()

{

char *cp;

int i;

i = cp;

}

   

file:5: warning: assignment makes integer from pointer without a cast

   

top-level declaration of `XXX' specifies `auto'

함수 바깥에 선언된 선언에 `auto' 키워드가 쓰였습니다. `auto' 키워드는 자동 변수 [automatic variable]를 선언하기 위해 쓰는 것이므로 전역 변수 [global variable]에 쓰일 수 없습니다.

auto int i;

   

file:1: top-level declaration of `i' specifies `auto'

   

register name not specified for `XXX'

`register' 키워드는 자주 쓰이는 변수를 메모리 대신 (가능하다면 [if possible]) CPU의 레지스터 [register]를 쓰도록 합니다. 전역 변수 [global variable]에는 `register' 키워드를 쓸 수 없습니다.

register int i;

   

file:1: register name not specified for `i'

   

redeclaration of `XXX'

같은 스코프 [scope] 안에 같은 이름이 쓰인 경우에 발생합니다. 다른 변수 이름을 써야 할 것입니다. 이 에러는 `XXX' previously declared here 에러와 함께 발생합니다.

void foo()

{

int i;

int i;

i = 3;

}

   

file:4: redeclaration of `i'

file:3: `i' previously declared here

   

`XXX' previously declared here

같은 스코프 [scope] 안에 같은 이름이 쓰인 경우에 처음 선언한 곳을 나타내 줍니다. 이 에러는 redeclaration of `XXX' 에러와 함께 발생합니다.

void foo()

{

int i;

int i;

i = 3;

}

   

file:4: redeclaration of `i'

file:3: `i' previously declared here

   

`#include' expects "FILENAME" or <FILENAME>

`#include'에 쓰이는 파일 이름은 `"'나 `<>'로 둘러싸야 합니다.

#include stdio.h

   

file:1: `#include' expects "FILENAME" or <FILENAME>

   

numeric constant contains digits beyond the radix

주어진 수치 상수 [numeric constant]가 진법에 맞지 않을 경우에 발생합니다. 예를 들어 8 진수에서 쓰일 수 있는 숫자는 0, 1, ..., 7인데 아래의 예처럼 8을 쓴다거나, 16 진수에서 쓰일 수 있는 문자는 a, b, ..., f인데 f 이후의 문자를 쓸 경우에 발생합니다.

int i = 08;

int j = 0xah;

   

file:1: numeric constant contains digits beyond the radix

file:2: numeric constant contains digits beyond the radix

   

`#' operator is not followed by a macro argument name

`#' 매크로 연산자는 매크로 인자 [argument] 앞에 나와 이 이 인자를 문자열 [string]로 만들어주는 역할을 합니다. `#' 연산자가 매크로 이름 앞에 나오지 않은 경우에 이 에러가 발생합니다.

#define bug(s)        s #

   

file:1: `#' operator is not followed by a macro argument name

   

`##' at start of macro definition

`##' 매크로 연산자는 두 개의 인자 [argument]를 받아 이들을 하나의 토큰 [token]으로 바꾸어 줍니다. 따라서 `##' 연산자는 `+' 연산자처럼 쓰이며 양쪽에 인자가 와야 합니다. `##' 연산자 앞에 인자가 오지 않을 때 이 에러가 발생합니다.

#define bug(s)        ## s

   

file:1: `##' at start of macro definition

   

`##' at end of macro definition

`##' 매크로 연산자는 두 개의 인자 [argument]를 받아 이들을 하나의 토큰 [token]으로 바꾸어 줍니다. 따라서 `##' 연산자는 `+' 연산자처럼 쓰이며 양쪽에 인자가 와야 합니다. `##' 연산자 뒤에 인자가 오지 않을 때 이 에러가 발생합니다.

#define bug(s)        s ##

   

file:1: `##' at end of macro definition

   

`XXX' defined as wrong kind of tag

struct이나 union, enum을 써서 한 형을 만들때, 이 때 사용한 tag (예를 들어 struct s;에서 tag는 `s'가 됩니다.)가 다른 타입에서 쓰일 때 이 에러가 발생합니다.

struct s { int x, y, z; };

void f()

{

union s foo;

foo.x = 1;

}

   

file:4: `s' defined as wrong kind of tag

   

negative width in bit-field `XXX'

bit field에서 bit 갯수를 지정할 때 음수 [negative number]나 0을 쓸 수 없습니다.

struct s { int x : -3; };

   

file:1: negative width in bit-field `x'

   

warning: width of `XXX' exceeds its type

Bit field의 크기가 주어진 형의 크기를 넘을 경우 발생합니다. 크기가 큰 다른 형으로 바꾸거나 bit field의 크기를 줄여 해결할 수 있습니다.

struct s { char c : 20; };

   

file:1: warning: width of `c' exceeds its type

   

break statement not within loop or switch

`break' 키워드는 switch, while, do-while, for 내부에서만 쓰일 수 있습니다. `break'를 다른 곳에서 쓸 경우 이 에러가 발생합니다.

void f()

{

break;

}

   

file:3: break statement not within loop or switch

   

request for member `XXX' in something not a structure or union

`.' 연산자는 구조체 [structure]나 union에서 멤버 [member]를 엑세스하기 위해 사용하며, 구조체나 union이 아닌 곳에서 `.'를 사용할 경우에 이 에러가 발생합니다. 대개의 경우, 구조체의 이름을 틀리게 썼을 경우에 발생합니다.

struct s { int i; };

void f()

{

char c;

c.i = 3;

}

   

file:5: request for member `i' in something not a structure or union

   

char-array initialized from wide string

C 언어는 여러 나라의 언어를 지원하기 위해 multibyte 문자인 wide character를 지원합니다. Wide character 상수는 문자 상수나 문자열 앞에 'L'을 붙여 나타내며 이 형은 wchar_t (<stddef.h>에 정의되어 있습니다) 입니다. 이 에러는 wchar_t 형 문자열을 char 형 배열에 초기값으로 쓸 때 발생합니다. 배열을 wchar_t 형으로 선언하거나 초기값을 char 형 상수를 써서 이 에러를 해결할 수 있습니다.

char a[] = L"abc";

   

file:1: char-array initialized from wide string

   

declaration of `XXX' as array of voids

void 형은 포인터 형으로 쓰거나 함수의 return 값으로 쓰이는 경우에만 의미가 있습니다. 다른 경우, 예를 들어 void 형 배열을 선언하는 것은 옳지 않습니다.

void a[3];

   

file:1: declaration of `a' as array of voids

   

invalid macro name `defined'

프리프로세서 [preprocessor]의 연산자인 `defined'는 매크로 이름으로 정의될 수 없으며, 정의를 취소할 수도 없습니다.

invalid macro name `XXX' 에러를 참고하시기 바랍니다.

#undef defined

#define defined        abc

   

file:1: invalid macro name `defined'

file:2: invalid macro name `defined'

   

#undef 4

   

file:1: invalid macro name `4'

   

invalid type argument of `unary *'

단항 연산자 [unary operator] `*'는 포인터 앞에서 이 포인터가 가리키는 것을 역참조 [dereference]하기 위해 쓰입니다. `*' 연산자가 포인터가 아닌 다른 형에 쓰이면 이 에러가 발생합니다.

void f()

{

int i;

*i = 3;

}

   

file:4: invalid type argument of `unary *'

   

arithmetic on pointer to an incomplete type

아직 완전하게 정의가 알려지지 않은 형에 대해서 포인터 연산을 수행할 수 없습니다. 아래의 예에서 이 에러가 발생하지 않게 하려면 먼저 `struct s' 형의 정의를 내려야 합니다.

struct s;

void g(struct s*);

void f()

{

struct s *p;

g(p + 1);

}

   

file:6: arithmetic on pointer to an incomplete type

   

XXX: No such file or directory

`#include'에서 쓴 파일을 찾을 수 없을 때 이 에러가 발생합니다. 대개 이 에러는 사용자가 만든 파일을 `"' 대신 `<>'로 둘러싸거나 파일 이름을 틀리게 입력하거나, 또는 컴파일러 옵션에서 디렉토리 설정이 잘못되어 있는 경우, 컴파일러에서 쓰이는 환경 변수 [environment variable]가 잘못 지정되어 있는 경우에 발생합니다. 자세한 것은 GCC 문서(info)에서 `-I' 옵션이나 `C_INCLUDE_PATH' 환경 변수를 참고하시기 바랍니다.

#include <where_is_it.h>

   

file:1: where_is_it.h: No such file or directory

   

variable or field `XXX' declared void

변수나 field는 void 형으로 선언할 수 없습니다.

저자가 쓰고 있는 GCC 2.7.2는 전역 변수 [global variable]로 `void a;'를 선언하면 이 에러를 만들지 않습니다. 이는 버그인 것으로 생각되는데, 이 문제에 대해 도움을 주실 수 있는 분은 알려 주시면 감사하겠습니다. 연락처는 이 문서의 처음에 있습니다.

void foo()

{

void a;

}

   

file:3: variable or field `a' declared void

file:4: warning: unused variable `a'

   

`XXX' has both `extern' and initializer

함수의 내부에서 `extern'으로 선언된 오브젝트 [object]는 초기값 [initializer]을 가질 수 없습니다. `XXX' initialized and declared `extern' 경고를 참고하시기 바랍니다.

extern int i = 1;

void f()

{

extern int j = 3;

}

   

file:1: warning: `i' initialized and declared `extern'

file: In function `f':

file:4: `j' has both `extern' and initializer

tmp.c:4: warning: unused variable `i'

   

warning: `XXX' initialized and declared `extern'

`extern'으로 선언된 오브젝트 [object]에 초기값 [initializer]을 주면 `extern'은 무시됩니다. `XXX' has both `extern' and initializer 에러를 참고하시기 바랍니다.

extern int i = 1;

void f()

{

extern int j = 3;

}

   

file:1: warning: `i' initialized and declared `extern'

file: In function `f':

file:4: `j' has both `extern' and initializer

tmp.c:4: warning: unused variable `i'

   

function `XXX' is initialized like a variable

함수로 선언 [declaration]된 이름은 초기값 [initializer]을 가질 수 없습니다.

int f(void) = 3;

   

file:1: function `f' is initialized like a variable

   

parameter `XXX' is initialized

예전 방식 [old style]으로 선언된 함수에서 파라메터 [parameter]는 초기값 [initializer]을 가질 수 없습니다.

void f(i)

int i = 3;

{

}

   

file:2: parameter `i' is initialized

   

typedef `XXX' is initialized

`typedef'는 기존의 형에 대해 새 형 이름 [type name]을 정의하는 것이기 때문에 초기값 [initializer]을 가질 수 없습니다.

typedef int INT = 1;

   

file:1: typedef `INT' is initialized

   

No such file or directory

컴파일러가 주어진 파일 이름 (디렉토리 포함)을 찾을 수 없을 때 발생합니다. 대개 파일 이름을 틀리게 입력했을 때 발생합니다.

gcc where_is_it.c

   

where_is_it.c: No such file or directory

   

macro or `#include' recursion too deep

매크로나 `#include'가 재귀적으로 너무 깊게 반복될 때 발생합니다. 예를 들어 `util.h'가 `types.h'를 포함 (#include)하고, `types.h'가 다시 `util.h'를 포함하는 경우, 이들 파일을 소스에 포함시키면, 서로가 서로를 계속 포함시키게 되므로 결국 컴파일러는 이 에러를 발생시킵니다. 이럴 때에는 `#ifndef', `#define', `#endif' 등을 써서 재귀적으로 포함되지 않게 해서 해결합니다.

#include "util.h"

   

file:1: macro or `#include' recursion too deep

   

invalid use of undefined type `XXX'

주어진 형이 완전히 정의되지 않은 상태에서 이 형을 사용할 수 없습니다. 아래의 예에서는 함수 g()의 return 형이 `struct s'이지만 `struct s'는 아직 정의되지 않았습니다. 이 때 g()를 부르는 것은 옳지 않습니다. 이 문제를 해결하려면 함수 g()를 부르기 전에 먼저 `struct s'를 정의해야 합니다.

void f()

{

struct s g();

g();

}

   

file:4: invalid use of undefined type `struct s'

   

attempt to take address of bit-field structure member `XXX'

Bit field에는 `address of' 연산자인 `&'를 쓸 수 없습니다.

struct s { int i : 3; };

void f()

{

struct s p;

int *ip = &p.i;

}

   

file:5: attempt to take address of bit-field structure member `i'

file:5: warning: unused variable `ip'

   

warning: address of register variable `XXX' requested

`register'로 선언 [declaration]된 변수에 `address of' 연산자를 쓸 경우에 발생합니다. `register'를 쓴다고 항상 CPU의 레지스터에 이 변수가 저장되는 것은 아니지만, 실제 CPU 레지스터의 사용 여부에 상관없이 `register'를 쓴 변수의 주소를 얻는 것은 옳지 않습니다.

void f()

{

register int i;

int *ip = &i;

ip = 0;

}

   

file:4: warning: address of register variable `i' requested

   

`sizeof' applied to a bit-field

Bit-field에는 `sizeof' 연산자를 쓸 수 없습니다.

struct s { int i : 3; };

void f()

{

struct s p;

int i = sizeof(p.i);

i = 3;

}

   

file:5: `sizeof' applied to a bit-field

   

warning: case value out of range

`case'에서 쓴 상수식 [constant expression]은 `switch'에서 쓴 데이터 형의 범위를 넘을 수 없습니다. 아래의 예에서는 `case'의 상수식 0xffffff가 `char' 형의 범위를 넘었기 때문에 발생합니다. 이 문제를 해결하려면 `switch'에서 쓴 데이터의 형을 좀 더 큰 형 (예를 들어 `int')으로 바꾸어야 합니다.

void f()

{

char c;

switch (c) {

case 0xffffff:

;

}

}

   

file:5: warning: case value out of range

   

case label not within a switch statement

`case'는 `switch' 구조 안에서만 쓸 수 있습니다.

void f()

{

case 4:

;

}

   

file:3: case label not within a switch statement

   

character constant too long

정수안에 들어가기에는 너무 많은 문자를 가지고 있는 상수를 쓸 때에 이 에러가 발생합니다.

int i = 'abcde';

   

file:1: character constant too long

   

warning: escape sequence out of range for character

문자 상수나 문자열에 쓰인 escape sequence가 너무 큰 값을 가지고 있어 문자 [unsigned char]로 표현할 수 없을 때 이 경고가 발생합니다. 이러한 값들은 적절하게 잘라내 [truncate] 버립니다.

char *p = "\x1ff\400";

   

file:1: warning: escape sequence out of range for character

file:1: warning: escape sequence out of range for character

   

continue statement not within a loop

`continue' 키워드는 루프 [loop] (for, while, do-while) 안에서만 의미가 있습니다. `continue'를 루프 밖에서 쓰는 것은 옳지 않습니다.

void foo()

{

continue;

}

   

file:3: continue statement not within a loop

   

invalid operands to binary X

X는 바이너리 연산자 (예: +, -, *, /, ==, !=, <=, >= 등)이며, 연산자의 오퍼랜드 형은 스칼라 [scalar] 형이어야 합니다. 즉 정수나 실수이어야 하며, 구조체 [structure]나 union 형이 올 수 없습니다.

이 에러는 조건식 [conditional expression]이 필요한 if, for, while, do-while 등에서 구조체나 union형을 쓸 때에도 발생합니다.

또 이 에러는 형이 다른 포인터에 연산을 취할 때에도 발생할 수 있습니다.

struct s { int i; };

void f()

{

struct s p;

int i = (p != 0);

   

while (p) {

}

}

   

file: In function `f':

file:5: invalid operands to binary !=

file:7: invalid operands to binary !=

file:5: warning: unused variable `i'

   

void f()

{

char *cp;

int *ip;

int i;

i = ip - cp;

}

   

file: In function `f':

file:6: invalid operands to binary -

이 에러는 조건식인 `? :'을 쓸 때에도 발생합니다. 조건식 `e1 ? e2 : e3'는 `e1'이 참일 경우, `e2'가 평가되고, 거짓일 때에는 `e3'가 평가됩니다. 이 때 이 조건식은 `if (e1 != 0) e2 else e3'로 취급되므로 만약 `e1'이 스칼라 형이 아니면 이 에러가 발생합니다.

struct s { int x; } st;

   

void f(void)

{

int i = st ? 3 : 4;

}

   

file: In function `f':

file:5: invalid operands to binary !=

file:5: warning: unused variable `i'

   

warning: overflow in implicit constant conversion

주어진 상수를 함축적으로 [implicitly] 변환 [conversion]할 때 오버플로우 [overflow]가 발생할 때 이 경고가 발생합니다. 아래의 예는 `int' 형의 범위를 넘는 실수 상수 (double 형)를 `int' 형에 대입하려 하는 경우를 나타냅니다.

int i = 1e300;

   

file:1: warning: overflow in implicit constant conversion

   

warning: declaration of `XXX' shadows a parameter

함수 내부에서 이 함수에 전달되는 파라메터 [parameter]와 같은 이름을 선언한 경우에 발생합니다. 즉 파라메터의 이름이 새 선언 [declaration]에 의해 가려졌으므로 이 선언이 나온 다음부터는 이 이름을 가진 파라메터를 쓸 수 없습니다. 이 경우, 둘 중 하나를 다른 이름을 갖게 고치는 것이 좋습니다.

void f(int i, int INT)

{

int i;

i = 3;

}

   

file:3: warning: declaration of `i' shadows a parameter

   

warning: data definition has no type or storage class

데이터 (함수나 변수등)를 정의할 때 형을 쓰지 않을 경우 발생합니다. 일반적으로 함수나 변수의 return 형을 쓰지 않을 때 발생하며, 이 때에는 `int' 형으로 간주됩니다.

i;

f();

   

file:1: warning: data definition has no type or storage class

file:2: warning: data definition has no type or storage class

   

default label not within a switch statement

`default' 키워드는 `switch' 문 [statement] 안에서만 쓸 수 있습니다.

void f()

{

default:

;

}

file:3: default label not within a switch statement

   

invalid macro name `XXX'

매크로 이름은 유효한 [valid] C 언어 이름 [identifier]이 나와야 합니다. 즉 첫글자는 [_a-zA-Z]이며, 두번째 글자부터는 [_a-zA-Z0-9]입니다. 아래의 예에서 `3'은 이름 [identifier]이 될 수 없기 때문에 이 에러가 발생합니다.

invalid macro name `defined' 에러도 참고하시기 바랍니다.

#define 3

   

file:1: invalid macro name `3'

   

invalid format `#line' directive

`#line' 지시어 [directive] 뒤에는 라인 번호를 의미하는 수치가 나와야 합니다. 이 수치는 0이 아닌 양수 [positive number]이어야 합니다.

invalid #-line 에러를 참고하시기 바랍니다.

#line 02a

   

file:1: invalid format `#line' directive

   

warning: unknown escape sequence `\x'

문자열에서 `\' 뒤에 오는 문자는 특정한 뜻이 있는 몇 개의 문자만 쓸 수 있습니다. 예를 들어 `\n'은 newline 문자를 나타내고, `\t'는 tab 문자를 나타냅니다. 이를 `escape sequence'라고 하며, 알려지지 않은 문자가 `escape sequence'로 쓰인 경우 이 경고가 발생합니다. 이 때 쓰인 `\x'는 일반 문자 `x'로 취급됩니다.

int i = '\q';

   

file:1: warning: unknown escape sequence `\q'

   

duplicate case value

두 `case' 문장에서 같은 상수 값이 쓰였을 때 발생합니다.

void f()

{

int a = 3;

switch (a) {

case 1:

case 1:

default:

break;

}

}

   

file: In function `f':

file:6: duplicate case value

file:5: this is the first entry for that value

   

   

multiple default labels in one switch

`switch' 문장 안에서 `default' 레이블이 두 개 이상 쓰였을 경우 발생합니다.

void f()

{

int a = 3;

switch (a) {

case 1:

default:

default:

break;

}

}

   

file: In function `f':

file:7: multiple default labels in one switch

file:6: this is the first default label

   

duplicate member `XXX'

`struct'이나 `union'에서 같은 이름이 두 개 이상의 멤버에 쓰였을 때 이 에러가 발생합니다. 각각 다른 이름을 써서 이 에러를 없앨 수 있습니다.

struct s {

int i;

float i;

};

   

file:3: duplicate member `i'

   

`#elif' after `#else'

선택적 컴파일을 할 수 있는 `preprocessor directive'인 `#if', `#elif', `#else', `#endif'에서 `#elif'는 항상 `#else' 앞에 나와야 합니다.

#if defined(ONE)

int i = 1;

#elif defined(TWO)

int i = 2;

#else

int i = 3;

#elif defined(FOUR)

int i = 4;

#endif

   

file:7: `#elif' after `#else'

(matches line 1)

   

   

`#XXX' not within a conditional

`Preprocessor directive'인 `#else'나 `#elif'는 `#if'나 `#ifdef', `#ifndef' 등의 if 섹션의 일부로 쓰여져야 합니다. `#elif'가 단독으로 쓰였을 경우 이 에러가 발생합니다.

#elif defined(TWO)

int i = 2;

#endif

   

file:1: `#elif' not within a conditional

file:3: unbalanced `#endif'

   

   

#else

int i = 2;

#endif

   

file:1: `#else' not within a conditional

file:3: unbalanced `#endif'

   

   

invalid initializer

`struct'이나 `union'의 초기값을 중괄호({})로 싸지 않는 등, 잘못된 초기값을 썼을 때 이 에러가 발생합니다.

struct s {

int x;

int y;

} st = 1;

   

file:4: invalid initializer

   

enumerator value for `AA' not integer constant

Enumerator로 쓰일 수 있는 상수는 반드시 정수형 값을 가져야 합니다. 실수(real)나 다른 상수가 아닌 값이 쓰이면 이 에러가 발생합니다.

enum A { AA = 0.1, BB = 2 };

   

file:1: enumerator value for `AA' not integer constant

   

warning: parameter names (without types) in function declaration

함수의 선언은 ANSI 방식과 옛 방식 중 하나를 쓸 수 있습니다. 옛 방식은 함수의 인자 리스트를 쓰지 않고, ANSI 방식은 인자의 타입과 갯수를 꼭 지정해야 합니다. 아래의 예에서는 함수 f의 인자인 `i'의 타입을 지정하지 않았기 때문에 이 경고가 발생한 것입니다.

int f(i);

   

file:1: warning: parameter names (without types) in function declaration

   

undefined or invalid # directive

#abc

   

file:1: undefined or invalid # directive

   

invalid preprocessing directive name

# 0x12

   

file:1: invalid preprocessing directive name

   

   

conflicting types for `XXX'

int i;

long i;

   

file:2: conflicting types for `i'

file:1: previous declaration of `i'

   

   

redefinition of `XXX'

int i = 0;

int i = 1;

   

file:2: redefinition of `i'

file:1: `i' previously defined here

   

   

empty #if expression

#if

int i = 2;

#endif

   

file:1: empty #if expression

   

unterminated `#if' conditional

#ifdef A

int i = 1;

   

file:1: unterminated `#if' conditional

   

warning: `#ifdef' with no argument

#ifdef

int i = 1;

#endif

   

file:1: warning: `#ifndef' with no argument

   

#ifndef

int i = 1;

#endif

   

warning: implicit declaration of function `XXX'

void f()

{

g();

}

   

file:3: warning: implicit declaration of function `g'

   

void value not ignored as it ought to be

int f()

{

void g();

   

int i = (int)g();

return i;

}

   

file: In function `f':

file:5: void value not ignored as it ought to be

   

   

structure has no member named `XXX'

struct abc {

int a, b;

};

   

void f()

{

struct abc a;

a.c = 0;

}

   

cf. union도 같음

file: In function `f':

file:8: structure has no member named `c'

   

   

warning: initialization makes integer from pointer without a cast

int i = "abc";

   

file:1: warning: initialization makes integer from pointer without a cast

   

badly punctuated parameter list in `#define'

#define max(a

   

file:1: badly punctuated parameter list in `#define'

   

storage size of `XXX' isn't known

struct s st;

   

file:1: storage size of `st' isn't known

   

file:

   

file:

   

file:

   

file:

   

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

readv 함수 예제  (0) 2012.07.30
poll 함수 예제  (0) 2012.07.26
GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24
select 함수 예제  (0) 2012.07.23
Unix Domain Socket 예제  (0) 2012.07.23
semget. semop, semctl 함수 예제  (0) 2012.07.17

[다중 입출력 함수 select]

I/O 처리하는 경우 non-blocking 으로 여러개의 file descriptor를 체크하면서

읽어들일 데이터가 어떤 상태인지 확인하다가, 어떤 변화가 생기면

file descriptor를 리턴하게 된다.

만일 아무런 변화가 없다면 block 상태에 걸려버리는데

이는 timeout을 지정해서 빠져나올 수 있게 한다.

이 기능을 가지고 sleep대신 select를 사용할 수도 있다.

 

개인적으로 이해가 잘 안되서 이래저래 좀 자세히 테스트 해봤다.

 

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

 

내용출처 : http://mintnlatte.tistory.com/313

- nfds : 검사 대상이 되는 fd 범위로 세개의 집합(readfds/writefds/exceptfds)중 가장 큰 파일 디스크립터 값에 1을 더해서 전달하는 매개변수

- readfds : 시스템에 의해 즉시 입력이 가능한지 확인(읽기가 block되지 않았는지 검사하기 위한 리스트/ EOF 발생 검사)

- writefds : 시스템에 의해 즉시 출력이 가능한지 확인(쓰기가 block되지 않았는지 검사하기 위한 리스트)

- exceptfds : 예외가 있는지 검사하기 위한 리스트

- timeout : select가 반환하기 전에 블럭킹될 수 있는 시간의 제한 값 (0은 즉시반환 / NULL은 무한 block)

 

 ○ 리턴값

  -1 : 오류발생 

   0 : 타임아웃

양수: 변화 발생 파일 디스크립터 수

 

: FD_SET 구조체 / 변수 조작하는데 사용되는 함수들

 

○ FD_SET 구조체

 

 typedef struct fd_set {

    u_int          fd_count;

    SOCKET    fd_array[FD_SETSIZE];

 } fd_set;

- fd_count : 설정하는 파일 디스크립터의 번호

- fd_array : 설정된 파일 디스크립터의 배열

* fd_set은 0과 1로 저장되는 비트들의 배열이다.

 

○ FD_SET 변수 조작 함수

  - FD_SETFD_ZERO(fd_set *fdset) : fdset 포인터가 가리키는 변수의 모든 비트들을 0으로 초기화

  - FD_SET(int fd, fd_set *fdset) : fdset 포인터가 가리키는 변수에 fd로 전달되는 파일 디스크립터의 정보 설정(1로 설정)

  - FD_CLR(int fd, fd_set *fdset) : fdset 포인터가 가리키는 변수에 fd로 전달되는 파일 디스크립터의 정보를 삭제(0으로 설정)

  - FD_ISSET(int fd, fd_set *fdset) : fdset 포인터가 가리키는 변수가 fd로 전달되는 파일 디스크립터의 정보를 지니는지 확인

 

○ timeout 구조체

 

 

 struct timeval {

    long    tv_sec;

    long    tv_usec;

 }

-  tv_sec : 초 단위 설정 변수

- tv_usec : 마이크로 초 단위 설정 변수

 

 

 동작하는 방식

  FD_SET 변수에 변화가 생긴 파일 디스크립터는 1로 세팅, 변화가 없는 파일 디스크립터는 0으로 세팅한다.

 

 

- select 함수 호출 전 관찰 대상으로 fd0 과 fd3 이 설정되어 있다.

- select 함수 호출 후 fd3만 1로 설정되어있다.

=> fd3에 변화가 생겼음을 확인 & 해당 파일 디스크립터와 데이터 통신을 진행한다.

 

다음은 간단한 server/client를 구현했다. 그냥 echo 서버인데 서버쪽에서 여러개의

클라이언트를 그냥 받아들인다.

이걸 기본으로 하면 다른 것도 금방 짜겠다..

소스코드라인도 좀 기네;;;

 

==================================

 

서버측 소스코드
#include "sys/socket.h"
#include "sys/time.h"
#include "sys/types.h"
#include "sys/stat.h"
#include 
#include 
#include 
#include 
#include "netinet/in.h"
#include "arpa/inet.h"

#define FD_MAX_SIZE 1024

int main(int argc, char **argv)
{
    int server_sockfd, client_sockfd, sockfd;
    int state, client_len;
    int pid;
    int i, max_client, maxfd;
    int client[FD_MAX_SIZE];

    FILE *fp;
    struct sockaddr_in clientaddr, serveraddr;
    struct timeval tv;
    fd_set readfds, otherfds, allfds;

    int current_cli_num;
    char buf[255];
    char line[255];

    memset(line, 0x00, 255);
    state = 0;
    current_cli_num = 3;

    if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket error : ");
        exit(0);
    }

    memset(&serveraddr, 0x00, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(9000);

    state = bind(server_sockfd, (struct sockaddr *)&serveraddr,
            sizeof(serveraddr));
    if (state == -1) {
        perror("bind error : ");
        exit(0);
    }

    state = listen(server_sockfd, 5);
    if (state == -1) {
        perror("listen error : ");
        exit(0);
    }

    client_sockfd = server_sockfd;

    max_client = -1;
    maxfd = server_sockfd;

   for (i = 0; i < FD_MAX_SIZE; i++) {
        client[i] = -1;
    }

    FD_ZERO(&readfds);
    FD_SET(server_sockfd, &readfds);

    printf("\nTCP Server Waiting ...");
    fflush(stdout);

    while(1)
    {
        allfds = readfds;
        state = select(maxfd + 1 , &allfds, NULL, NULL, NULL);

        if (FD_ISSET(server_sockfd, &allfds)) {
            client_len = sizeof(clientaddr);
            client_sockfd = accept(server_sockfd,
                    (struct sockaddr *)&clientaddr, &client_len);
            printf("\nconnection from (%s , %d)",
                    inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));

            for (i = 0; i < FD_MAX_SIZE; i++)
            {
                if (client[i] < 0) {
                    client[i] = client_sockfd;
                    printf("\nclientNUM=%d\nclientFD=%d\n", i+1, client_sockfd);
                    break;
                }
            }

            printf("accept [%d]\n", client_sockfd);
            printf("===================================\n");
            if (i == FD_MAX_SIZE) {
                perror("too many clients\n");
            }
            FD_SET(client_sockfd,&readfds);

            if (client_sockfd > maxfd)
                maxfd = client_sockfd;

            if (i > max_client)
                max_client = i;

            if (--state <= 0)
                continue;

        }
        for (i = 0; i <= max_client; i++)
        {
            if ((sockfd = client[i]) < 0) {
                continue;
            }

            if (FD_ISSET(sockfd, &allfds))
            {
                memset(buf, 0x00, 255);

                if (read(sockfd, buf, 255) <= 0) {
                    close(sockfd);
                    perror("Close sockfd : ");
                    FD_CLR(sockfd, &readfds);
                    client[i] = -1;
                }
                printf("[%d]RECV %s\n", sockfd, buf);
                write(sockfd, buf, 255);

                if (--state <= 0)
                    break;
            }
        }
    }
}
클라이언트 측 소스코드
#include "sys/socket.h"
#include "sys/types.h"
#include "netinet/in.h"
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    int sock, bytes_recieved;
    char send_data[1024],recv_data[1024];
    struct hostent *host;
    struct sockaddr_in server_addr;

    host = gethostbyname("127.0.0.1");

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket");
        exit(1);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(9000);
    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
    memset(&(server_addr.sin_zero), 0x00, 8);

    if (connect(sock, (struct sockaddr *)&server_addr,
                sizeof(struct sockaddr)) == -1) {
        perror("Connect");
        exit(1);
    }

    while(1) {
        printf("\nSEND : ");
        fgets(send_data, sizeof(send_data), stdin);

        if (strcmp(send_data , "q") != 0 && strcmp(send_data , "Q") != 0)
            send(sock,send_data,strlen(send_data), 0);

        else {
            send(sock,send_data,strlen(send_data), 0);
            close(sock);
            break;
        }
        bytes_recieved=recv(sock,recv_data,1024,0);
        recv_data[bytes_recieved] = '\0';

        if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0) {
            close(sock);
            break;
        }
        else
            printf("\nRECV = %s\n " , recv_data);
    }
    return 0;
}
서버측의 결과 화면
TCP Server Waiting ...
connection from (127.0.0.1 , 53672)
clientNUM=1
clientFD=4
accept [4]
===================================

connection from (127.0.0.1 , 53681)
clientNUM=2
clientFD=5
accept [5]
===================================
[4]RECV nnnnnn

[5]RECV aaaaaa
클라이언트 측의 결과 화면
./aa_client

SEND : nnnnnn

RECV = nnnnnn

 

 

 

==================================

 

 

테스트하고 구현하는 건 자유인데 요러고 나니 아주쬐금 이해가 된다.

 

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

poll 함수 예제  (0) 2012.07.26
GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24
select 함수 예제  (0) 2012.07.23
Unix Domain Socket 예제  (0) 2012.07.23
semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17

내부 프로세스끼리 TCP 또는 UDP 프로토콜을 이용해서 통신하도록

도와주는 소켓이다. 아래의 예제를 보면 이 앞의 다른 IPC 통신과는 달리

특정 함수 API가 제공되지는 않는다. 기존의 TCP/IP 통신하는 소스코드와 거의 동일함.

 

 

================================================

 

서버측 소스 코드
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/socket.h"
#include "sys/un.h"
#include 
#include 
#include 
#include 

#define MAXLINE 1024 

int main(int argc, char **argv)
{
    int server_sockfd, client_sockfd;
    int state, client_len;
    pid_t pid;

    FILE *fp;
    struct sockaddr_un clientaddr, serveraddr;

    char buf[MAXLINE]; 

    if (argc != 2) {
        printf("Usage : %s [socket file name]\n", argv[0]);
        exit(0);
    }

    if (access(argv[1], F_OK) == 0) {
        unlink(argv[1]);
    }

     client_len = sizeof(clientaddr);
     if ((server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
         perror("socket error : ");
         exit(0);
     }
     bzero(&serveraddr, sizeof(serveraddr));
     serveraddr.sun_family = AF_UNIX;
     strcpy(serveraddr.sun_path, argv[1]);

     state = bind(server_sockfd , (struct sockaddr *)&serveraddr,
             sizeof(serveraddr));
     if (state == -1) {
         perror("bind error : ");
         exit(0);
     }

     state = listen(server_sockfd, 5);
     if (state == -1) {
         perror("listen error : ");
         exit(0);
     }
     while(1)
     {
         client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr,
                 &client_len);
         pid = fork();
         if (pid == 0)
         {
             if (client_sockfd == -1) {
                 perror("Accept error : ");
                 exit(0);
             }

             while(1)
             {
                 memset(buf, 0x00, MAXLINE);
                 if (read(client_sockfd, buf, MAXLINE) <= 0) {
                     close(client_sockfd);
                     exit(0);
                 }
                 printf("RECV-> %s\n", buf);
                 write(client_sockfd, buf, strlen(buf));
             }
         }
     }
     close(client_sockfd);
}
클라이언트 측 소스코드
#include 
#include "sys/un.h"
#include 
#include 
#include 

#define MAXLINE 1024 


int main(int argc, char **argv)
{

    int client_len;
    int client_sockfd;

    FILE *fp_in;
    char buf_in[MAXLINE]; 
    char buf_get[MAXLINE]; 

    struct sockaddr_un clientaddr;

    if (argc != 2) {
        printf("Usage : %s [file_name]\n", argv[0]);
        exit(0);
    }

    client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_sockfd == -1) {
        perror("error : ");
        exit(0);
    }

    bzero(&clientaddr, sizeof(clientaddr));
    clientaddr.sun_family = AF_UNIX;
    strcpy(clientaddr.sun_path, argv[1]);
    client_len = sizeof(clientaddr);

    if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) < 0)
    {
        perror("Connect error: ");
        exit(0);
    }
    while(1)
    {
        memset(buf_in, 0x00, MAXLINE); 
        memset(buf_get, 0x00, MAXLINE); 
        printf("> "); 
        fgets(buf_in, MAXLINE, stdin);
        write(client_sockfd, buf_in, strlen(buf_in));
        read(client_sockfd, buf_get, MAXLINE);
        printf("-> %s", buf_get);
    }

    close(client_sockfd);
    exit(0);
}
서버측 결과화면
RECV-> opipoipoikl

RECV-> 1

클라이언트측 결과화면
INPUT-> opipoipoikl
RECV-> opipoipoikl
INPUT-> 1
RECV-> 1

================================================

 

 

테스트하는 경우 %[실행파일명] [통신에 사용할 파일명]

저 파일을 설정해주고 사용하는 것만

다르고 나머지는 기본 TCP/IP와 동일하다.

 

다시 보니 이해가 좀 되네..

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

GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24
select 함수 예제  (0) 2012.07.23
Unix Domain Socket 예제  (0) 2012.07.23
semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13

+ Recent posts