2. C

2.1. 컴파일 하기(make 사용함)

hello.c 소스
#include <stdio.h>

main()
{
  printf ("This is test program");
}
    
hello.c 소스

hello.c 컴파일하기

gcc -o hello hello.c

./hello
This is test program
    

※ gcc 옵션

c 언어는 기본적으로 컴파일을 먼저 해서 object 화일을 만들어 줍니다.

그리고 나서 link를 해주어서 실행 화일을 만들어 줍니다.

-o name : 실행 화일 이름을 정해서 만들어 준다.

-c : 컴파일만 한다.

make 사용하기
# all 명령을 실행한다.
all:   excute 

# 오프젝트 화일을 만든다.
object:     hello.o

# 실행 화일 만든다.
excute :        hello

# 오프젝트 화일을 지운다.
clean:
            rm -f collage *.o
    

make 실행
cc    -c hello.c -o hello.o
cc   hello.o   -o hello
    

이때 오프 젝트 화일이 없어야 한다.(*.o)

hello 실행
This is test program
    

2.2. make 사용할수 있도록 만들기

autoscan

mv configure.scan configure.in

configure.in 수정
dnl Process this file with autoconf to produce a configure script.
AC_INIT()

AC_CONFIG_HEADER(config.h)

dnl Checks for programs.

.....
.....
.....

AC_OUTPUT( Makefile )
    

aclocal

autoheader

autoconf

automake (--add-missing)

./configure

2.3. 모듈(라이브러리) 기초

  1. 정적 라이브러리

    .a

  2. 공유 라이브러리

    .so, .sa

  3. 정적 라이브러의 단점은 동시에 여러 프로그램을 띄웠을 경우 이들이 모두 같은 라이브러리의 함수들을 사용함으로써 메모리에 같은 함수들을 여러 번 복사하고, 프로그램 파일에도 같은 라이브러리를 여러 번 복사를 한다는 것이다.

    이는 메모리 용량과 디스크 용량을 많이 소모한다. 많은 유닉스 시스템에서는 이러한 불편함을 극복할 수 있도록 공유 라이브러리를 제공한다.

  4. python 공유 모듈 만들기
    #!/bin/bash
    
    echo $1
    
    if [ $# = 0 ] ;then
        echo "사용법 : 확장자(.c)를 뺀 소스 이름을 입력하세요."
        exit 0
    fi
    swig -python -module $1 $1.c
    gcc -c $1.c $1_wrap.c -I/usr/include/python1.5 -I/usr/lib/python1.5/config
    ld -shared $1.o $1_wrap.o -o $1module.so
            

2.4. talk_server

대화방 서버 입니다.

컴파일 : gcc -o talker_server talk_server.c

실행 : talk_server 3000

소스
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 512

char * escapechar = "exit";

int main(int argc, char * argv[]) 
{
int server_fd, client_fd;
int clilen, num;

char sendline[MAXLINE], recvline[MAXLINE];

int size;
pid_t pid;
struct sockaddr_in client_addr, server_addr;

  if(argc != 2) 
  {
    printf("사용법 : %s port  ", argv[0]);
    exit(0);
  }

  if((server_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
  {
    printf("Server : Can't open stream socket ");
    exit(0);
  }

  bzero((char *) & server_addr, sizeof(server_addr));

  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_port = htons(atoi(argv[1]));

  if(bind(server_fd, (struct sockaddr *) & server_addr, sizeof(server_addr)) < 0) 
  {
    printf("Server : Can't bind local address");
    exit(0);
  }

  printf("Server started. Waiting for client.. ");
  listen(server_fd, 1);

  clilen = sizeof(client_addr);
  if((client_fd = accept(server_fd, (struct sockaddr *) & client_addr, &clilen)) < 0) 
  {
    printf("Server : failed in accepting.");
    exit(0);
  }

  if(( pid = fork()) > 0) 
  {
    while(fgets(sendline, MAXLINE, stdin ) != NULL) 
    {
      size = strlen(sendline);
      if(write(client_fd, sendline, strlen(sendline)) != size) printf("Error in write ");
      if(strstr(sendline, escapechar) != NULL) 
      {
        printf("Good bye.");
        close(client_fd);
        exit(0);
      }
    }
  } else if (pid == 0) 
  {
  while(1) 
  {
    if((size = read(client_fd, recvline, MAXLINE)) < 0) 
    {
      printf("Error if read ");
      close(client_fd);
      exit(0);
    }

    recvline[size] = '';
    if(strstr(recvline, escapechar) != NULL) break;

    printf("%s", recvline);
    }
  }

  close(server_fd);
  close(client_fd);
}
    

2.5. talk_client

대화방 클라이언트 입니다.

컴파일 : gcc -o talk_client talk_client.c

실행 : talk_client SERVERIP 3000

소스
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 1024

char *escapechar = "exit";

int main(int argc, char *argv[]) 
{
  char line[MAXLINE], sendline[MAXLINE], recvline[MAXLINE+1];

  int n, size, comp;

  pid_t pid;

  static int s;

  static struct sockaddr_in server_addr;

  if(argc != 3) 
  {
    printf("사용법 : %s server_IP port ", argv[0]);
    exit(0);
  }

  if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
  {
    printf("Client: Can't open stream socket. ");
    exit(0);
  }

  bzero((char *) & server_addr, sizeof(server_addr));

  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(argv[1]);
  server_addr.sin_port = htons(atoi(argv[2]));

  if(connect(s, (struct sockaddr *) & server_addr, sizeof(server_addr)) < 0) 
  {
    printf("Client: can't connect to server. ");
    exit(0);
  }

  if(( pid = fork()) > 0) 
  {
    while(fgets(sendline, MAXLINE, stdin) != NULL) 
    {
      size = strlen(sendline);
      if(write(s, sendline, strlen(sendline)) != size) printf("Error in write ");

      if(strstr(sendline, escapechar) != NULL) 
      {
        printf("Good bye. ");
        close(s);

        exit(0);
      }
    }
  } else if(pid == 0) 
  {
    while(1) 
    {
      if((size = read(s, recvline, MAXLINE)) < 0) 
      {
        printf("Error if read ");
        close(s);
      }
      recvline[size] = '';
      if(strstr(recvline, escapechar) != NULL) break;

      printf("%s", recvline);
    }
  }
  close(s);
}
    

2.6. 인자 처리 함수

프로그램 실핼할때의 인자 처리 방법입니다.
#include <stdio.h>

char *programname; // usage()

char a;
char *b = "";
unsigned int d = 1;

void usage ();

main(int argc, char **argv)
{
char option;
extern char *optarg;
programname = argv[0]; // 프로그램 이름을 변수에 넣는다.

  if (argc < 2) usage (); // 인자가 없으면 usage() 함수 호출

  while ((option = getopt (argc, argv, "a:b")) != -1) 
  { // 인자 처리 함수 
    switch (option) 
    {
      case 'a':
        a = 1;
        break;
      case 'b':
        b = optarg;
        break;
      default:
        usage ();
    }
  }

  printf("a : %d , b : %s", a, b);
}

void usage ()
{
    printf ("사용법 : %s [-a 인자] [-b 인자] [-c 인자] [-d 인자]", programname);
    exit (1);
}
    

2.7. daytime.c 소스입니다.

daytime.c 소스입니다.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUF_LEN 128

int main(int argc, char *argv[]) 
{
int sockfd, n;

char *haddr;
struct sockaddr_in server_addr; /* 서버 주소를 넣을 구조체 */
char buf[BUF_LEN + 1];

  if(argc != 2) 
  {
    printf("사용법 : %s ip_address", argv[0]);
    exit(0);
  }

  haddr = argv[1];

  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) 
  {
    printf("소켓을 만들수 없습니다.");
    exit(0);
  }

  bzero((char *) &server_addr, sizeof(server_addr)); /* 초기화를 해준다. */

  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(13); /* daytime 서버 포트를 설정한다. */
  server_addr.sin_addr.s_addr = inet_addr(argv[1]);

  if(connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
  {
    printf("서버 포트에 접속을 할수 없습니다.");
    exit(0);
  }

  while((n = read(sockfd, buf, BUF_LEN)) > 0) 
  {
    buf[n] = '';
    if(fputs(buf, stdout ) == EOF) printf("aaaa");
  }

  close(sockfd);
}
    

2.8. 시그널 함수

콘트롤 키의 조합 할때 사용하는 함수 입니다.

시그널 함수 : /usr/include/bits/signum.h

컴파일 : gcc -o signal_test signal_test.c

실행 : ./signal_test

소스
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

int my_signal(void); // 새로운 시그널 함수를 선언한다.
int count = 0;  // ctrl-c 입력 횟수 카운터

int main()
{
  int i = 0;

  if(signal(SIGINT, my_signal) == SIG_ERR) 
  { // 시그널 함수를 작동 시킨다.
    printf("singal() error");
    exit(0);
  }

  while(count < 3) 
  { // contrl-c 입력이 3번까지 
    sleep(1); // 1초가 정지
    printf("%d", i++); //  ctrl-c 카운터
  }

}

int my_signal(void)
{
  printf("Ctrl-C pressed. ");
  count++;
  return 0;
}
    

2.9. 호스트 이름 알아내는 프로그램

컴파일 : gcc -o test test.c

소스1
#include <stdio.h>
#include <fcntl.h>

int main()
{
    char hostname[124];
    FILE *fd;
    fd = fopen("/proc/sys/kernel/hostname", "r");

    fread(hostname, sizeof(hostname), 1, fd);
    printf("%s", hostname);

    return 0;
}
    

소스2
#include <unistd.h>
#include <netdb.h>

main ()
{
  struct hostent* hoststruct;
  char hostname[255];

  gethostname(hostname, 100);
  hoststruct = gethostbyname(hostname);
  printf("호스트 이름은 %s 입니다.\n", hoststruct->h_name);
}
    

2.10. 다국어 테스트 프로그램(gettext)

  1. hello.po를 만들어 준다.

    xgettext -a -d hello -k_ -s hello.c

  2. mo 화일을 만들어 주는 사용법입니다.

    msgfmt hello.po

    messages 라는 화일이 생기는데 이것을 이름을 바꾸어 주면 됩니다.

    mv hello.po hello.mo

  3. 로케일 디렉토리에 카피를 합니다.

    cp hello.mo /usr/share/locale/ko/LC_MESSAGES/hello.mo

  4. 소스를 컴파일 합니다.

    gcc -o hello hello.c

  5. 소스
    #include <locale.h>
    #include <stdio.h>
    #include <libintl.h>
    #define _(String) gettext (String)
    
    int main(void)
    {
        setlocale (LC_ALL, "");
        bindtextdomain ("hello", "/usr/share/locale/");
        textdomain ("hello");
    
        puts (_("hello"));
    }
           

  6. hello.po
    #: hello.c:24
    #, fuzzy
    msgid ""
    msgstr ""
    "Project-Id-Version: 1.0\n"
    "POT-Creation-Date: 2001-03-08 17:06+0900\n"
    "PO-Revision-Date: 2001-03-08 17:06+0900\n"
    "Last-Translator: Kim Yong Il <nalabi@formail.org>\n"
    "Language-Team: Uniwork Project Team <nalabi@formail.org>\n"
    "MIME-Version: 1.0\n"
    "Content-Type: text/plain; charset=ecu-kr\n"
    "Content-Transfer-Encoding: 8-bit\n"
    
    #: hello.c:25 hello.c:26 hello.c:28
    msgid "hello"
    msgstr "안녕하세요
            

  7. Makefile
    # Makefile for locale directory
    
    CWD = locale
    MSGFMT = msgfmt
    SUB_DIRS =
    FILES_PO:=$(wildcard *.po)
    FILES_MO:=$(FILES_PO:.po=.mo)
    
    LOCALEDIR ?= /usr/share/locale
    
    ifeq ($(enable_nls),1)
    all: mo-files
    
    mo-files: $(FILES_MO)
    
    install:
        $(MAKE) all
        for f in *.mo ; do mkdir -p \
            $(INSTALL_PREFIX)$(LOCALEDIR)/`basename $$f .mo`/LC_MESSAGES ; \
            cp $$f $(INSTALL_PREFIX)$(LOCALEDIR)/`basename $$f .mo`/LC_MESSAGES/gkrellm.mo ; done
    
    %.mo: %.po
        $(MSGFMT) -f -v -o $@ $<
    
    else
    
    all:
    
    install:
    
    endif
    
    clean:
        $(RM) $(FILES_MO)
            

2.11. define 예제

  1. 소스
    #include "stdio.h"
    
    #define TEST(test)      my_func_##test()
    #define test(num)       __asm__ __volatile__("call test_" #num::);
    
    void my_func_hello(void)
    {
      printf("HELLO !!\n");
    }
    
    
    void my_func_goodbye(void)
    {
      printf("Good Bye !!\n");
    }
    
    
    void test_1(void)
    {
      printf("This is test_1 function\n");
    }
    
    
    void test_2(void)
    {
      printf("This is test_2 function\n");
    }
    
    
    main()
    {
      int i;
      TEST(hello);
      TEST(goodbye);
    
      test(1);
      test(2);
    }
            

  2. 컴파일

    gcc -o t test.c

  3. 실행
    HELLO !!
    Good Bye !!
    This is test_1 function
    This is test_2 function
          

2.12. 찾기를 원하는화일

소스
#include 

int ftw_find();

int main(int argc, char *argv[])
{
  if (argc > 1)
  {
    ftw(argv[1],ftw_find, 0);
  }
  else
  {
    printf("Usage: %s dir\n", argv[0]);
  }
  return 0;
}

int ftw_find(const char *path, struct stat *sb, int flag)
{
  if(strstr(path,"찾고자 하는 파일이나 디렉토리")!=NULL)
  {
    printf("%s:\t%u\t\n", path, sb->st_size);
    exit(0);
  }
  return 0;
}
    

2.13. 커널 시스템 콜 함수

unistd.h 헤더

/usr/src/linux-2.4.18# vi include/asm/unistd.h
#define __NR_lremovexattr   236
#define __NR_fremovexattr   237
#define __NR_mycall         238
    

entry.S

/usr/src/linux-2.4.18# vi arch/i386/kernel/entry.S
    .long SYMBOL_NAME(sys_ni_syscall)   /* reserved for lremovexattr */
    .long SYMBOL_NAME(sys_ni_syscall)   /* reserved for fremovexattr */
    .long SYMBOL_NAME(sys_mycall) 		/* 238 mycall */
    

mycall.c

/usr/src/linux-2.4.18# vi kernel/mycall.c
#include <linux/kernel.h>
#include <linux/errno.h>

asmlinkage void sys_mycall()
{       
    printk("Corea Manse!!!!\n");
} 
    

krernel/Makefile

/usr/src/linux-2.4.18# vi kernel/Makefile
obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
        module.o exit.o itimer.o info.o time.o softirq.o resource.o \
        sysctl.o acct.o capability.o ptrace.o timer.o user.o \
        signal.o sys.o kmod.o context.o mycall.o
    

user Makefile
COMPILE=gcc

INCLUDEDIR = /usr/src/linux-2.4.18/include

MODCFLAGS := -I$(INCLUDEDIR)

mycall_app : mycall_app.c

    $(COMPILE) $(MODCFLAGS) -o $@ $^
    

소스 (mycall_app.c)
#include <linux/unistd.h>

/* system call stub function */
_syscall0(void, mycall);

main()
{
  mycall();
}
    

2.14. 맥어드레스 알아내기

소스
#include <netinet/ether.h>
#include <net/ethernet.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>

int main (int argc, char *argv[])
{
  struct ifreq *iflist;
  struct sockaddr *sa;
  int fd;
  char *out;

  if(argc != 2) 
  {
    printf("Usage: progname ifname (ex: progname eth0)\n");
    return -1;
  }
 
  iflist = malloc (sizeof (struct ifreq));

  fd = socket (PF_INET, SOCK_STREAM, 0);

  strncpy (iflist->ifr_name, argv[1], strlen (argv[1]));

  if (ioctl (fd, SIOCGIFHWADDR, iflist) == -1)
  {
    perror ("ioctl failed");
    return -1;
  }

  sa = &(iflist->ifr_hwaddr);

  out = ether_ntoa ((struct ether_addr *) sa->sa_data);

  printf ("%s\n", out);

  return 0;
}