간단하게 리소스 카운터라고 생각해도 되는데 일단은 데드락 피하기 위한

기술 중의 하나라고 한다..

실제 어디다 써먹을지는 아직 모르겠지만.. 이거보다는 개인적으로 뮤텍스를 더 자주 쓰는듯 싶네..

 

소스코드 출처 : http://forum.falinux.com/zbxe/?document_srl=428639

 

int semget ( key_t key, int nsems, int semflg )

세마포어 식별자를 가지고 오는 함수다.

 

key_t key

시스템에서 세머포어를 식별하는 키 번호

int nsems

세마포어 집합 내의 세마포어 개수로 접급 제한하려는 세마포어 자원의 개수

int semflg 동작 옵션 ( IPC_CREATE와 IPC_EXCL이 있다.)

 

 

int semctl ( int semid, int semnum, int cmd, union semun arg)

세마포어를 control 하는 함수다.

 

int semid 시스템에서 세머포어를 식별하는 집합 번호
int semnum

세마포어 집합 내에서의 세마포어 위치 (세마포어 넘버...)

int cmd

제어 명령( 값을 설정, 삭제, 소유권, 등등 많다.)

union semun arg 위의 제어명령 cmd 에 따라 달라진다., 설정 또는 값을 구하는 변수 
union semun{
   int                  val;
   struct   semid_ds   *buf;
   unsigned short int  *arrary;
}

int semop ( int semid, struct sembuf *sops, unsigned nsops )

세마포어의 값을 변경한다. 값을 증가, 감소시킨다.

 

int semid 시스템에서 세머포어를 식별하는 집합 번호
struct sembuf *sops

세마포어 값을 계산하기위한 설정 값 
struct sembuf {
    short sem_num;   세마포어 번호
    short sem_op;     세마포어 증감값
    short sem_flg;     옵션 
}

unsigned nsops

변경하려는 세마포어 개수로 변경하려는 세마포어 개수가 여러 개일 때 사용
n개의 세마포어 옵션들..

 

 

예제를 봐야 이게 뭔지 조금은 이해가 간다.

매우간단한 멀티 쓰레드 구조의 카운터다.

failinux.com.. 참 괜찮다.

 

 

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

#include 
#include 
#include 
#include 
#include "sys/ipc.h"
#include "sys/sem.h"
#include "sys/poll.h"

int         cnt   = 0;
static int  semid;

void semop1() 
{
    struct sembuf buf1;

    buf1.sem_num   = 0;
    buf1.sem_op    = -1;
    buf1.sem_flg   = SEM_UNDO;

    if (semop(semid, &buf1, 1) == -1)
        printf( "%s::semop() Fail\n", __func__);
}

void semop2()
{
    struct sembuf buf2;

    buf2.sem_num   = 0;
    buf2.sem_op    = 1;
    buf2.sem_flg   = SEM_UNDO;

    if (semop(semid, &buf2, 1) == -1)
        printf( "%s::semop() Fail\n", __func__);
}

void *fun_thread1(void *arg) {
    while( 1) {
        semop1();
        printf( "thread1 run \n");
        if ( 5 < cnt) {
            printf( "thread1 Completely terminated \n");
            semop2();
            break;
        }
        else {
            cnt++;
            poll(0,0,100);
            printf( "thread1 terminated \n");
        }
        semop2();
    }
    return;
}

void *fun_thread2(void *arg)
{
    while( 1) {
        semop1();
        printf( "thread2 run \n");
        if (5 < cnt) {
            printf( "thread2 Completely terminated \n");
            semop2();
            break;
        }
        else {
            printf( "=====>>Counter= %d\n", cnt);
            poll(0,0,100);
            printf( "thread1 terminated \n");
        }
        semop2();
    }

    return;
}

int main(int argc, char *argv[])
{
    pthread_t thread1;
    pthread_t thread2;
    union semun{
        int                  val;
        struct   semid_ds   *buf;
        unsigned short int  *arrary;
    }arg;

    if ((semid = semget( IPC_PRIVATE, 1, IPC_CREAT| 0666)) == -1) {
        printf( "semget() Fail\n");
        return -1;
    }

    arg.val=1;                // Semaphore value = 1
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        printf( "semctl()-SETVAL Fail\n");
        return -1;
    }

    pthread_create(&thread1, NULL, fun_thread1, NULL);
    pthread_create(&thread2, NULL, fun_thread2, NULL);
    pthread_join( thread1, NULL);
    pthread_join( thread2, NULL);

    if (semctl(semid, 0, IPC_RMID, arg) == -1) {
        printf( "semctl()-IPC_RMID Fail\n");
        return -1;
    }
    printf( "Process Terminated!");
    return 0;
}
/* The end of function */
# 수행결과는 다음과 같다.
./a.out
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 1
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 2
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 3
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 4
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 5
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
thread2 Completely terminated 
thread1 run 
thread1 Completely terminated 

 

 

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

 

failinux 그대로 가져왔슴..

개인적인 테스트용이므로,, 저작권에 문제가 있다면

알려주시길.. 지우던지 다른 방식으로 구현해두겠습니다.

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

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
C FAQ (포인터 증가 3)  (0) 2012.07.13
파일이나 디바이스를 주소 공간 메모리에 대응시키는 방식인데

일종의 IPC 통신으로 사용가능하다. 매우 빠름.

 

출처 : 소스코드 http://www.cs.purdue.edu/homes/fahmy/cs503/mmap.txt

 

void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);

파일이나 디바이스를 응용 프로그램의 주소 공간 메모리에 대응시킨다.

 

1인자 => 시작 포인터 주소 (아래의 예제 참조)

2인자 => 파일이나 주소공간의 메모리 크기

3인자 => PROT 설정 (읽기, 쓰기, 접근권한, 실행)

4인자 => flags는 다른 프로세스와 공유할지 안할지를 결정한다.

5인자 => fd는 쓰거나 읽기용으로 열린 fd값을 넣어준다.

6인자 => offset은 0으로 하던지 알아서 조절한다.

 

int munmap(void* start, size_t length);

할당된 메모리 영역을 해제한다.

 

1인자 => 위에 mmap으로 지정된 포인터값 넣어주고

2인자 => 위에서 사용했던 length와 동일하게 넣어준다.

(왜냐면.. 할당했던거 동일하게 해제해야 하니깐..)

 

더 자세한 사항은 man page에 모든게 나와있음.

 

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

#include 
#include 
#include 
#include 
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/mman.h" /* mmap() is defined in this header */

int main (int argc, char *argv[])
{
    int fdin, fdout;
    char *src, *dst;
    struct stat statbuf;

    if (argc != 3) {
        printf("usage: a.out  \n");
        return -1;
    }

    /* open the input file */
    if ((fdin = open (argv[1], O_RDONLY)) < 0) {
        printf ("can't open %s for reading", argv[1]);
        return -2;
    }
    /* open/create the output file */
    if ((fdout = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) {
        printf ("can't create %s for writing", argv[2]);
        return -2;
    }

    /* find size of input file */
    if (fstat (fdin,&statbuf) < 0) {
        printf ("fstat error");
        return -2;
    }

    /* go to the location corresponding to the last byte */
    if (lseek (fdout, statbuf.st_size - 1, SEEK_SET) == -1) {
        printf ("lseek error");
        return -2;
    }

    /* write a dummy byte at the last location */
    if (write (fdout, "", 1) != 1) {
        printf ("write error");
        return -2;
    }
    /* mmap the input file */
    if ((src = mmap(0, statbuf.st_size, PROT_READ,
                    MAP_SHARED, fdin, 0)) == (caddr_t) -1)
    {
        printf ("mmap error for input");
        return -2;
    }

    /* mmap the output file */
    if ((dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE,
                    MAP_SHARED, fdout, 0)) == (caddr_t) -1)
    {
        printf ("mmap error for output");
        return -2;
    }

    /* this copies the input file to the output file */
    memcpy (dst, src, statbuf.st_size);

    munmap(src, statbuf.st_size);
    munmap(dst, statbuf.st_size);

    return 0;
} /* main */
/* The end of function */
실행 후 결과 화면 
$ ./a.out test test_out
$ ls -al
drwxr-xr-x  2 jeon jeon 4096 Jul 17 08:39 .
drwx------ 12 jeon jeon 4096 Jul 17 08:39 ..
-rwxr-xr-x  1 jeon jeon 6410 Jul 17 08:39 a.out
-rw-r--r--  1 jeon jeon 1844 Jul 17 08:39 mmap.c
-rw-r--r--  1 jeon jeon  469 Jul 17 08:29 test
-rw-------  1 jeon jeon  469 Jul 17 08:39 test_out

 

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

 

test라는 입력파일은 미리 생성하고

test_out은 위의 프로그램을 실행하고 생성된 파일이다.

생각보다 간단한것 같은데.

최대 어느정도까지 매핑시키는지는 추후에 해봐야겠다..

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

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
C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12

IPC 통신의 그다음 핵심인 Shared Memory 이용이다.

 

출처 : http://www.cs.cf.ac.uk/Dave/C/node27.html ,  http://failinux.com

 

int shmget(key_t key, int size, int shmflg);

 

key_t key 공유 메모리를 구별하는 식별 번호
int size 공유 메모리 크기
int shmflg 동작 옵션

 

 

void *shmat(int shmid, const void *shmaddr, int shmflg);

 

int shmid 공유 메모리를 구별하는 식별 번호
void *shmaddr 첨부되는 어드레스 주소. 일반적으로 NULL을 지정
int shmflg

동작 옵션

key값만 서로 맞추면 제대로 동작한다.

예제코드는 shm_server와 shm_client이고

서버쪽은 메모리에 쓰는역할

클라이언트쪽은 메모리에서 읽는 역할을 한다.

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

==== shm_server.c ====
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include 

#define SHMSZ     27

int main()
{
    char c;
    int shmid;
    key_t key;
    char *shm, *s;

    /* We'll name our shared memory segment
     * "5678".  */
    key = 9678;

    /* Create the segment.  */
    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
        perror("shmget");
        return -1;
    }

    /* Now we attach the segment to our data space.  */
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        return -1;
    }

    /* Now put some things into the memory for the
     * other process to read.  */
    s = shm;

    for (c = 'a'; c <= 'z'; c++)
        *s++ = c;
    *s = NULL;

    /*
     * Finally, we wait until the other process 
     * changes the first character of our memory
     * to '*', indicating that it has read what 
     * we put there.
     */
    while (*shm != '*')
        sleep(1);

    return 0;
}
==== shm_client.c ====
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include 

#define SHMSZ     27

int main()
{
    int shmid;
    key_t key;
    char *shm, *s;

    /* We need to get the segment named
     * "5678", created by the server.  */
    key = 5678;

    /* Locate the segment.  */
    if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
        perror("shmget");
        return -1;
    }

    /* Now we attach the segment to our data space.  */
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        return -1;
    }

    /* Now read what the server put in the memory.  */
    for (s = shm; *s != NULL; s++)
        putchar(*s);
    putchar('\n');

    /*
     * Finally, change the first character of the 
     * segment to '*', indicating we have read 
     * the segment.
     */
    *shm = '*';

    return 0;
}
== 서버측은 결과가 나오지않는다. ==
== 클라이언트측 결과는 다음과 같다. ==
$ ./clie 
abcdefghijklmnopqrstuvwxyz

 

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

 

위의 프로그램은 a-z까지 출력하는건데

키값은 5678이다. 이걸 16진수로 변환하면 162e가 되는데 이건

%ipcs 명령으로 확인하면 생성된것을 볼 수 있다.

---- 중략 ----

0x0000162e 4292650    test      666        27         2

---- 후략 ----

 

위에서 define으로 결정한 크기를 넘어서게 되면 앞쪽은 잘리고

뒤에만 출력되게 된다.

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

semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13
C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12
msgsnd/ msgrcv 함수 예제  (0) 2012.07.12

출처 : www.cfaq.com

Q: I have a char * pointer that happens to point to some ints, and I want to step it over them. Why doesn't

((int *)p)++;

work?

int 형 포인터인데 왜 저렇게는 증가가 안되는건가?   

A: In C, a cast operator does not mean ``pretend these bits have a different type, and treat them accordingly''; it is a conversion operator, and by definition it yields an rvalue, which cannot be assigned to, or incremented with ++. (It is either an accident or a deliberate but nonstandard extension if a particular compiler accepts expressions such as the above.) Say what you mean: use

        p = (char *)((int *)p + 1);

or (since p is a char *) simply

        p += sizeof(int);

or (to be really explicit)

        int *ip = (int *)p;
        p = (char *)(ip + 1);

When possible, however, you should choose appropriate pointer types in the first place, rather than trying to treat one type as another.

See also question 16.7.

References: K&R2 Sec. A7.5 p. 205

ISO Sec. 6.3.4

Rationale Sec. 3.3.2.4

H&S Sec. 7.1 pp. 179-80

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

mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13
C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12
msgsnd/ msgrcv 함수 예제  (0) 2012.07.12
C FAQ (포인터 증가 2)  (0) 2012.07.12

fread, fwitte, calloc 등에서 나온다.

calloc의 man page를 보다보면 아래와 같이 나온다.

  void *calloc(size_t nmemb, size_t size);

nmemb 는 number of members이고 간단하게

count정도로 여기면 된다.

더 간단히.. 개수..


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

shmget/ shmat 함수 예제  (0) 2012.07.13
C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12
msgsnd/ msgrcv 함수 예제  (0) 2012.07.12
C FAQ (포인터 증가 2)  (0) 2012.07.12
C FAQ (포인터 증가에 대해서)  (0) 2012.07.12

출처.: http://www.falinux.com/


IPC의 시작인 메시지큐 통신이다.

 

       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

 

int msqid

메시지 큐  식별자 , msgget 함수의 리턴값이다.

void *msgp

전송할 자료, void 포인터니까 아무 자료형이나 덮어쓰면된다.

size_t msgsz

전송할 자료의 크기, 자료가 구조체건 뭐건 sizeof로 정확한 크기면 된다.

int msgflg

동작 옵션, 큐에 공간이 있을떄까지 기다리면 0, 여유공간 없으면 복귀 시킬경우, IPC_NOWAIT.

 

 

       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

 

int msqid

메시지 큐 식별자, msgget 함수의 리턴값.

void *msgp

전송할 자료, 마찬가지로 아무 자료형이나 선언하기 나름.

size_t msgsz

전송할 자료의 크기, 위에 선언한거에 그냥 sizeof로 정확한 사이즈로 기재하면되고

logn msgtyp

int msgflg

수신할 메시지 타입, 0이면 다 받고 0보다 크면 큐에 가장 처음 메시지에서 타입이 같은거만 받고

동작 옵션

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

=== 메시지 수신하는 코드 ===
#include 
#include 
#include 
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/msg.h"

#define  BUFF_SIZE   1024
#define  KEY   35002

typedef struct {
    int   msgid;
    long  type;
    char  buff[BUFF_SIZE];
} t_data;

int main()
{
    int      msqid;
    t_data   data;

    printf("t_data size = %d\n", sizeof(t_data));
    printf("long size = %d\n", sizeof(long));

    if (( msqid = msgget( (key_t)KEY, IPC_CREAT|0666)) == -1) {
        perror( "msgget() fail");
        return -1;
    }

    while(1)
    {
        /* IPC message recv */
        if(msgrcv(msqid, &data, sizeof(t_data)-sizeof(long), 1, 0) == -1)
        {
            perror( "msgrcv() fail");
            return -2;
        }
        printf( "ID=[%d] MSG => %s\n", data.msgid, data.buff);
    }

    return 0;
}
/* end of the program */
===수신측 결과=== 
ID=[1] MSG => msg_type=0,index=1, message queue program
ID=[1] MSG => msg_type=10,index=11, message queue program
=== 메시지 송신하는 코드 ===
#include 
#include 
#include 
#include 
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#include 

#define  BUFF_SIZE   1024
#define  KEY         35002

typedef struct {
    int   msgid;
    long  type;
    char  buff[BUFF_SIZE];
} t_data;

int main()
{
    int      msqid;
    int      index   = 0;
    int      ret   = 0;
    t_data   data;

    printf("t_data size = %d\n", sizeof(t_data));
    printf("long size = %d\n", sizeof(long));

    if((msqid = msgget((key_t)KEY, IPC_CREAT|0666))== -1) {
        perror( "msgget() Fail");
        return -1;
    }

    while(1)
    {
        data.type  = index;
        data.msgid =  ((index++ %10)+1);

        sprintf( data.buff, "msg_type=%ld,index=%d, message queue program",
                data.type, index);

        printf( "ID=[%d]  MSG => %s\n", data.msgid, data.buff);

        /* IPC message send */
        ret = msgsnd(msqid, &data, (sizeof(t_data)-sizeof(long)), 0);
        if(ret == -1)
        {
            perror( "msgsnd() Fail");
            return -2;
        }
        /* sleep 2 seconde */
        poll(0, 0, 2000);
    }
    return 0;
}
===송신측 결과 ===
ID=[1]  MSG => msg_type=0,index=1, message queue program
ID=[2]  MSG => msg_type=1,index=2, message queue program
ID=[3]  MSG => msg_type=2,index=3, message queue program
ID=[4]  MSG => msg_type=3,index=4, message queue program
ID=[5]  MSG => msg_type=4,index=5, message queue program
ID=[6]  MSG => msg_type=5,index=6, message queue program
ID=[7]  MSG => msg_type=6,index=7, message queue program
ID=[8]  MSG => msg_type=7,index=8, message queue program
ID=[9]  MSG => msg_type=8,index=9, message queue program
ID=[10]  MSG => msg_type=9,index=10, message queue program
ID=[1]  MSG => msg_type=10,index=11, message queue program
ID=[2]  MSG => msg_type=11,index=12, message queue program

 

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

위에 보면 10으로 나눈 나머지에서 1이 되는 경우에만 수신하도록 구현되어 있다.

 

가장 중요한 부분은

메시지 사이즈 부분에 sizeof(long)만큼을 뺴주었는데

그 이유는 아래와 같다...

전에 이거 몰라서 찾는데 일주일 날린것만 생각하면.. 치가 떨린다...

 

struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};

The mtext field is an array (or other structure) whose size is specified by msgsz, a nonnegative integer value.


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

C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12
msgsnd/ msgrcv 함수 예제  (0) 2012.07.12
C FAQ (포인터 증가 2)  (0) 2012.07.12
C FAQ (포인터 증가에 대해서)  (0) 2012.07.12
C-FAQ 어찌되었건 pointer 쓰면 정말 좋은가?  (0) 2012.07.12

출처 http://c-faq.com

Q: I'm trying to use pointers to manipulate an array of ints. What's wrong with this code?

        int array[5], i, *ip;
        for(i = 0; i < 5; i++) array[i] = i;
        ip = array;
        printf("%d\n", *(ip + 3 * sizeof(int)));

I expected the last line to print 3, but it printed garbage.

   scaleing을 위해서 뒤에다가 sizeof(int)를 곱해줬는데 이걸로 인해서 존재하지 않는 영역을
건드리게 되면 위와 같이 에러가 난다. 게다가 sizeof(int)는 내가 사용하는 장비에 따라 싸이즈도
다르다. 포인터에서는 자동적으로 스케일되기 때문에 사이즈에 대한 고려는 해주지 않아도
된다는 내용.

A: You're doing a bit more work than you have to, or should. Pointer arithmetic in C is always automatically scaled by the size of the objects pointed to. What you want to say is simply

        printf("%d\n", *(ip + 3));        /* or ip[3] -- see Q 6.3 */

which will print the third element of the array. In code like this, you don't need to worry about scaling by the size of the pointed-to elements--by attempting to do so explicitly, you inadvertently tried to access a nonexistent element past the end of the array (probably array[6] or array[12], depending on sizeof(int) on your machine).

See, however, question 7.19b.

References: K&R1 Sec. 5.3 p. 94

K&R2 Sec. 5.4 p. 103

ISO Sec. 6.3.6

H&S Sec. 7.6.2 p. 204

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

nmemb 의미  (0) 2012.07.12
msgsnd/ msgrcv 함수 예제  (0) 2012.07.12
C FAQ (포인터 증가 2)  (0) 2012.07.12
C FAQ (포인터 증가에 대해서)  (0) 2012.07.12
C-FAQ 어찌되었건 pointer 쓰면 정말 좋은가?  (0) 2012.07.12
C FAQ (malloc 오류)  (0) 2012.07.12

출처 http://c-faq.com

Q: Does *p++ increment p, or what it points to?

   

A: The postfix ++ and -- operators essentially have higher precedence than the prefix unary operators. Therefore, *p++ is equivalent to *(p++); it increments p, and returns the value which p pointed to before p was incremented. To increment the value pointed to by p, use (*p)++ (or perhaps ++*p, if the evaluation order of the side effect doesn't matter).

References: K&R1 Sec. 5.1 p. 91

K&R2 Sec. 5.1 p. 95

ISO Sec. 6.3.2, Sec. 6.3.3

H&S Sec. 7.4.4 pp. 192-3, Sec. 7.5 p. 193, Secs. 7.5.7,7.5.8 pp. 199-200

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

msgsnd/ msgrcv 함수 예제  (0) 2012.07.12
C FAQ (포인터 증가 2)  (0) 2012.07.12
C FAQ (포인터 증가에 대해서)  (0) 2012.07.12
C-FAQ 어찌되었건 pointer 쓰면 정말 좋은가?  (0) 2012.07.12
C FAQ (malloc 오류)  (0) 2012.07.12
C FAQ (포인터 선언 에러)  (0) 2012.07.12

+ Recent posts