2014. 6. 13. 11:36

* pthread_create

 헤더

 #include  <pthread.h>

 원형

 int pthread_create(pthread_t * thread, const pthread_attr_t *attr,

     void* (*start_routine)(void*), void *arg);

 인자

 첫번째 : 생성된 스레드의 ID를 저장할 변수의 포인터 옴

 두번째 : 스레드 특징을 설정할때 사용됨, 주로 NULL이 옴

 세번째 : 스레드가 생성되고 나서 실행될 함수가 옴

 네번째 : 세번째 인자에서 호출될 함수에 전달하고자 하는 인자의 값


* pthread_join

 헤더

 #include <pthread.h>

 

 int pthread_join(pthread_t th, void **thread_return);

 인자설명

 첫번째 : 스레드 ID가 옴. 이 ID가 종료할 때까지 실행을 지연

 두번째 : 스레드 종료시 반환값 받음



정확하지 않은 tip!!

pthread_join의 반환값이 스레드 종료시 반환값인데,

스레드 종료할 때 return 보다는 pthread_exit 를 사용하는 것이 더 좋다!

(void * thr_fn1 을 void thr_fn1 로 잘못썻다가 계속 반환값을 이상한 값으로 받아오는 

 오류가 있었다. 스레드 종료값 넘겨줄 때는 pthread_exit가 더 좋은듯 )



예제코드

#include <pthread.h>

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>



void * thr_fn1(void *arg)

{

    printf("thread 1 returning \n");

    return ((void *) 1);

}


void * thr_fn2(void *arg)

{

    printf("thread 2 exiting \n");

    pthread_exit((void *)2);

}



int main(void)

{

    int err;

    pthread_t tid1, tid2;

    void *tret;


    err = pthread_create(&tid1, NULL, thr_fn1, NULL);

    if (err != 0 )

    {

        printf("can't create thread 1: %s\n", strerror(err));

        exit(err);

    }


    err = pthread_create(&tid2, NULL, thr_fn2, NULL);

    if(err != 0 )

    {

        printf("can't create thread 2 : %s\n", strerror(err));

        exit(err);

    }

    err = pthread_join(tid1, &tret);

    if (err != 0 )

    {

        printf("can't join with thread 1: %s\n", strerror(err));

        exit(err);

    }

    printf("thread 1 exit code %d\n", (int)tret);


    err = pthread_join(tid2, &tret);

    if ( err != 0 )

    {

        printf("can't jon with thread 2: %s\n", strerror(err));

        exit(err);

    }

    printf("thread 2 exit code %d\n", (int)tret);

    exit(0);

}


$ gcc 11-3.c -o 11-3 -lpthread

$ 11-3

thread 1 returning

thread 2 exiting

thread 1 exit code 1

thread 2 exit code 2



* 참고 : 유닉스 고급 프로그래밍 11-3 예제 참고

Posted by Triany
2014. 5. 22. 15:07


헤더 string.h

형태 size_t strlen( const char *str)

인수 char *str 길이를 구할 문자열

반환 문자열 길이를 바이트 단위로 반환합니다.


#include <stdio.h>

#include <string.h>

int main()

{

    char * a = "apple";

    printf ("length = %d,  %s \n" , strlen(a), a);

}

$ ./a.out

length = 5,  apple


Posted by Triany
2014. 5. 15. 17:41

[유닉스고급프로그래밍] 4-22 디렉터리 계통구조를 재귀적으로 따라 내려가면서 파일 종류 통계를 구하는 프로그램

APUE2 소스해석


#include "apue.h"

#include <dirent.h>

#include <limits.h>


typedef int Myfunc(const char * , const struct stat * , int);


static Myfunc myfunc;

static int myftw(char *, Myfunc *);

static int dopath(Myfunc * );


static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;


int main(int argc, char *argv[])

{

    int ret;

    if (argc != 2)

        err_quit("usage : ftw <starting-pathname>");


    ret = myftw(argv[1], myfunc); /*실제 잡업을 수행*/


    ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;


    if ( ntot == 0 )

        ntot = 1;


    printf("regular files = %7ld, %5.2f %%\n", nreg, nreg*100.0/ntot);

    printf("directories = %7ld, %5.2f %%\n", ndir, ndir*100.0/ntot);

    printf("block special = %7ld, %5.2f %%\n", nblk, nblk*100.0/ntot);

    printf("char special = %7ld, %5.2f %%\n", nchr, nchr*100.0/ntot);

    printf("FIFOS files = %7ld, %5.2f %%\n", nfifo, nfifo*100.0/ntot);

    printf("symbolic links = %7ld, %5.2f %%\n", nslink, nslink*100.0/ntot);

    printf("sockets = %7ld, %5.2f %%\n", nsock, nsock*100.0/ntot);


    exit(ret);


}


#define FTW_F 1

#define FTW_D 2

#define FTW_DNR 3

#define FTW_NS 4


static char * fullpath; /* 각파일의 전체 경로이름을 담음*/


//여기서 수행

static int myftw(char * pathname, Myfunc *func) /*func()의 반환값을 그대로 돌려줌 */

{

    int len;

    fullpath = path_alloc(&len); /*PATH_MAX+1*/ //apue에서 제공해주는 함수. 운영체제 환경에 따라 사용할 수 있는 공간의 최대 크기를 리턴해 주는 함수인듯.


    strncpy(fullpath, pathname, len);

    printf("fullpath: %s\n", fullpath);

    fullpath[len-1] = 0;


    return(dopath(func));

}



/* fullpath에서부터 계통구조를 따라간다

   fullpath가 디렉터리가 아니면 lstat()으로 정보를 얻어서

   func()를 호출하고 반환. 디렉터리면 그 디렉터리의 각 이름마다 이 함수를 재귀호출

*/

static int dopath(Myfunc * func)

{

    struct stat statbuf;

    struct dirent *dirp;

    DIR *dp;

    int ret;

    char *ptr;


    if ( lstat(fullpath, &statbuf) < 0 )

        return(func(fullpath, &statbuf, FTW_NS));
    if ( S_ISDIR(statbuf.st_mode) == 0 )
        return(func(fullpath, &statbuf, FTW_F));


    /*
     디렉터리면 우선 그 디렉터리에 대해 func()를 호출하고
     그 디렉터리의 각 파일이름을 처리한다.
     */
    if (( ret = func(fullpath, &statbuf, FTW_D)) != 0 )
        return(ret);

    ptr = fullpath + strlen(fullpath);  /* fullpath의 끝을 가리킨다*/

    *ptr++ = '/';
    *ptr = 0;

    if (( dp = opendir(fullpath)) == NULL ) /* 디렉터리를 읽을 수 없음 */
        return(func(fullpath, &statbuf, FTW_DNR));

    while (( dirp = readdir(dp)) != NULL ) {
        if ( strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0 )
            continue;
        strcpy(ptr, dirp->d_name); /*슬러시 다음에 이름을 추가 */

        if ( ( ret = dopath(func)) != 0 )
            break;

    }
    ptr[-1] = 0; /*슬래시 이후의 모든 것을 삭제 */

    if ( closedir(dp) < 0 )
        err_ret("can't close directory %s", fullpath);

    return(ret);
}

static int myfunc(const char * pathname, const struct stat * statptr, int type)
{
    printf("myfunc pathname : %s\n", pathname);
    switch(type) {
        case FTW_F:
            switch(statptr->st_mode & S_IFMT) //S_IFMT : bit mask for the file type bit fields! 00170000
            {
                case S_IFREG :  nreg++;     break;
                case S_IFBLK :  nblk++;     break;
                case S_IFCHR :  nchr++;     break;
                case S_IFIFO :  nfifo++;    break;
                case S_IFLNK :  nslink++;   break;
                case S_IFSOCK:  nsock++;    break;
                case S_IFDIR:
                    err_dump("for S_IFDIR for %s", pathname);
            }
            break;
        case FTW_D:
            ndir++;
            break;
        case FTW_DNR:
            err_ret("can't read directory %s", pathname);
            break;
        case FTW_NS:
            err_ret("stat error for %s", pathname);
            break;
        default:
            err_dump("unknown type %d for pathname %s", type, pathname);
    }
    return (0);
}

결과

./4-22-2 test

fullpath: test

myfunc pathname : test

myfunc pathname : test/Makefile

myfunc pathname : test/a.h

myfunc pathname : test/a.c

myfunc pathname : test/b.c

myfunc pathname : test/a.o

myfunc pathname : test/test

myfunc pathname : test/abc

myfunc pathname : test/abc/def

regular files =       6, 66.67 %

directories =       3, 33.33 %

block special =       0,  0.00 %

char special =       0,  0.00 %

FIFOS files =       0,  0.00 %

symbolic links =       0,  0.00 %

sockets =       0,  0.00 %



여기서 궁금했던 점은 

ret = dopath(func)에서 fullpath를 넘기지 않는데 어떻게 갱신이 될까? 하는 점이었다.


하지만 이 내용을 보면 알 수 있다.


#전역변수로 fullpath 선언

static char * fullpath; /* 각파일의 전체 경로이름을 담음*/


탐색할 디렉토리가 

다음의 구조와 같다고 가정하면

test / abd

     /  de


1. ptr = fullpath + strlen(fullpath);  /* fullpath의 끝을 가리킨다*/

2. *ptr++ = '/';
    *ptr = 0;

3.  strcpy(ptr, dirp->d_name); /*슬러시 다음에 이름을 추가 */


4. while문 돌고 나서 strcpy(ptr, dirp->d_name); /*슬러시 다음에 이름을 추가 */




이런식이랄까?

ptr 변수의 위치는 while문을 도는 내내 고정되 있어서 같은 디렉터리 내의 파일 이름을

덮어쓰는 형식으로 구현되어 있었다.

fullpath는 전역변수이기에 dopath할때 func 함수포인터만 넘겨도 되었던 것이고!


신기하기도 했던 내용이라 기록으로 남겨둔다.

Posted by Triany
2014. 5. 9. 18:34

#include <string.h> // C++ 에서는 <cstring>

void * memset ( void * ptr, int value, size_t num );

 


메모리 블록을 채운다.
ptr 로 시작하는 메모리 주소 부터 num 개의 바이트를 value 값으로 채운다. 이 때, value 는 unsigned char 로 형변환 된다. 

 

ex)

int * arrs = (int *)malloc(sizeof(int) * 7 )

memset(arrs, 0, sizeof(int) * 7)

 

arrs배열에 동적할당하고, 0으로 초기화 한다!

Posted by Triany
2011. 10. 6. 13:45


#include <stdio.h>
void main(){
    int a = 10000;
   printf("[d]  %d\n", a);
   printf("[x]  %08x\n", a);

    for (int i = 0; i < 32; i++)
    {
        a & (0x01 << (31 - i)) ? printf("1") : printf("0");
        if( (i+1) % 4 == 0 )
              printf(" ");

    }

    printf("(2)\n");
}


 #include <stdio.h>
void main(){
   int a;
   a = 0x7d9;
   printf("[d]  %d\n", a);

   //16진수로 출력
   printf("[x]  %08x\n", a);
 
   //8진수 출력
   printf("[o]  %08o\n", a);

    //2진수 표현
    for (int i = 0; i < 32; i++)
    {
      a & (0x01 << (31 - i)) ? printf("1") : printf("0");
      if( (i+1) % 4 == 0 )
        printf(" ");
     }
     printf("(2)\n");

 
      printf("   --- type 별 바이트수 ---\n");
     printf("\tchar  : %d bytes\n", sizeof(char));
     printf("\tshort : %d bytes\n", sizeof(short));
     printf("\tint   : %d bytes\n", sizeof(int));
    printf("\tlong  : %d bytes\n", sizeof(long));
 }




%o : 8진수
%x : 16진수
%d : 10진수

Posted by Triany
2011. 3. 7. 20:53
<const키워드 기능>
1. const 키워드는 변수의 선언 앞에 붙어서 변수를 상수화한다.
const double PI=3.14;
PI=3.1415; //컴파일 오류


2. const 키워드는 포인터가 가리키는 데이터를 상수화한다.
int n=10;
const int* pN=&n;
*pN=20; //컴파일 오류


3. const 키워드는 포인터 선언 시 이름 앞에 붙어서 포인터 자체를 상수화한다.
int n1=10;
int n2=20;
int* const pN=&n1;
*pN=20; //OK
pN=&n2; //컴파일 오류
=> 현재 pN은 끝까지 n1만을 가리켜야 한다.


참고: 열혈강의 C++

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

memset함수  (0) 2014.05.09
10진수 2진수, 8진수, 16진수로 표현 - - C Programming  (0) 2011.10.06
매크로와 전처리  (0) 2011.03.02
열거형(enum) 자료형  (0) 2011.03.01
문자열 처리함수  (0) 2011.03.01
Posted by Triany
2011. 3. 2. 23:10
#define으로 시작하는 전처리기 지시자(Preprocessor Directive)
:단순 치환 작업을 요청할 때 사용되는 지시자
(매크로 선언은 문장의 끝을 의미하는 세미콜론(;)을 붙여주지 않는다)
 #include <stdio.h>
 #define PI 3.1415
이때 PI는 마치 상수처럼 사용되고 있다. 따라서 이러한 PI를 매크로 상수라고 한다.

이런 매크로 상수를 이용하면 배열 선언도 가능하다.
 #include <stdio.h>
 #define NUM 10

 int main(void)
{
    int arr[num]={1,2,3,};

   ......
}


매크로를 이용한 함수의 구현
:함수의 기능을 하는 매크로 => 매크로 함수
 #define SQUARE(x)  x*x
 int a = SQUARE(2);
<매크로 함수의 이점>
1. 매크로 함수는 자료형에 독립적이다.
2. 실행 속도가 향상된다.
3. 함수의 크기가 작아야 함.

<매크로 함수의 단점>
함수의 구현이 까다롭고,
디버깅하기 어려우며,
구현하고자 하는 함수의 크기가 크다면 -> 프로그램의 크기가 커지게 됨.


##을 이용하면 토큰을 결합할 수있다.
#define CONCAT(a, b)  a ## b
Posted by Triany
2011. 3. 1. 23:36
의미1) days 라는 이름의 자료형(열거형)
의미2) 상수의 선언

사용하는 이유: 열거형을 사용함으로써 변수가 지니는 값에 의미를 부여할 수 있게 되고, 이에 따라 프로그램의 가독성이 더불어 높아지기 때문!

예제)

#include <stdio.h>
enum days {MON, TUE, WED, THU, FRI, SAT, SUN};

int main(void)
{
 enum days day;
 printf("Input a day(0:Monday ~ 6:Sunday) : ");
 scanf("%d", &day);

 switch(day)
 {
 case MON :
  printf("수영을 하세요.\n");
  break;
  
 case TUE :
  printf("조깅을 하세요.\n");
  break;
  
 case WED :
  printf("축구를 하세요.\n");
  break;
  
 case THU :
  printf("볼링을 하세요.\n");
  break;
  
 case FRI :
  printf("등산을 하세요.\n");
  break;
  
 case SAT :
  printf("탁구을 하세요.\n");
  break;
  
 case SUN :
  printf("원하는걸 하세요.\n");
  break;
 }
 return 0;
}



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

const키워드 기능  (0) 2011.03.07
매크로와 전처리  (0) 2011.03.02
문자열 처리함수  (0) 2011.03.01
문자단위 입.출력 함수(putchar, getchar, fputs, fgets)...etc  (0) 2011.02.28
배열포인터  (0) 2011.02.27
Posted by Triany
2011. 3. 1. 18:51
#include <string.h>

strcpy(str1, str2) :문자열 복사

strncpy(str1, str2, n) : n개만큼 문자열 복사(str2를 str1에)

strcat(str1, str2) :문자열 추가
strncat(str1, str2, n) :n개 만큼 문자열 추가

strcmp(str1, str2) :문자열 비교(같을 시 0을 반환)
strncmp(str1, str2, n)

strstr(str1, str2)
=>원형 : char* strstr(const char *str1, const char *str2)
str1안에 str2 문자열이 있으면 해당 문자열의 위치를 리턴
없으면 0(null)을 리턴



<문자열을 숫자로 변환하는 함수>
#include <stdlib.h>

int atoi(char *ptr); //문자열을 int형 데이터로 변화
long atol(char *ptr); //문자열을 long형 데이터로 변화
double atof(char *str); //문자열을 double형 데이터로 변환


<대소문자의 변환을 처리하는 함수들>
#include <ctypes.h>

int toupper(int c); //소문자를 대문자로
int tolower(int c); //대문자를 소문자로

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

매크로와 전처리  (0) 2011.03.02
열거형(enum) 자료형  (0) 2011.03.01
문자단위 입.출력 함수(putchar, getchar, fputs, fgets)...etc  (0) 2011.02.28
배열포인터  (0) 2011.02.27
포인터와 const키워드  (0) 2011.02.26
Posted by Triany
2011. 2. 28. 19:23
문자 단위 입출력 함수
1) 문자출력함수
 -하나의 문자를 출력할 때 일반적으로 사용하는 함수는 putchar함수와 fputc함수이다.
 int putchar(int c);
 int fputc(int c, FILE* stream);
◇putchar함수 : 함수 호출 시 인자로 전달된 문자를 '표준 출력 스트림(stdout)'으로 출력해주는 역할을 하는 함수. 즉 모니터에다가 하나의 문자를 출력해 주는 함수

◇fputc함수 : 함수 호출 시 인자로 전달된 문자를 '표준 출력 스트림(stdout)'으로 출력해주는 역할을 하는 함수. 즉 모니터에다가 하나의 문자를 출력해 주는 함수 +.. 문자를 출력할 스트림을 지정할 수 있다!(모니터뿐 아니라 파일에도 문자를 출력(저장)할 수 있는 함수)
fputc 함수의 두 번째 인자 stream은 문자를 출력할 스트림을 지정하기 위해서 사용된다. 따라서 이 인자에다가 표준 출력 스트림을 의미하는 'stdout'을 인자로 전달하게 되면 putchar함수와 완전히 동일한 함수가 된다. fputc함수는 파일 입.출력에서 주로 사용하게 된다.


※참고 : 오류 발생 시 반환되는 EOF의 실제 값을 -1이다.


2)문자 입력 함수
하나의 문자를 입력받을 때 일반적으로 사용하는 함수는 getchar함수와 fgetc함수이다.
 int getchar(void);
 int fgetc(FILE* stream);

◇getchar 함수: '표준 입력 스트림(stdin)'으로부터 한 문자를 입력받아서 반환해 주는 함수이다. 따라서 키보드로부터 하나의 문자를 입력받는 함수라고 할 수 있다.

◇fgetc함수:'표준 입력 스트림(stdin)'으로부터 한 문자를 입력받아서 반환해 주는 함수이다. 따라서 키보드로부터 하나의 문자를 입력받는 함수라고 할 수 있다.+.. 문자를 입력받을 스트림을 지정할 수 있다는 특징.(fgetc함수를 이용하면 키보드뿐만 아니라 파일로부터도 데이터를 입력받을 수 있다.)


#include <stdio.h>

int main()
{
 char ch=0;
 while(ch != 'q')
 {
  ch=getchar();    //fgetc(stdin)와 같다.
  putchar(ch);     //fputc(ch, stdout)와 같다.
 }

 return 0;
}



3)EOF에 대해서...
 오류 발생 혹은 파일의 끝에 도달했을 경우 EOF를 리턴.
 EOF가 실제로 지니고 있는 값을 -1이다.
 오류발생시 반환 + (fgetc나 getchar 함수가 파일의 끝에 도달하는 경우에도 EOF가 반환)
 getchar : 키보드로부터 Ctrl-Z키를 입력하는 경우에 EOF를 반환

 #include <stdio.h>

int main()
{
 char ch=0;
 while(ch != EOF)
 {
  ch=getchar();
  putchar(ch);
 }
 printf("program 종료 \n");

 return 0;
}



문자열 단위 입.출력함수
1)문자열 출력 함수
하나의 문자열을 출력할 때 일반적으로 사용하는 함수는 puts 함수와 fputs함수이다.
 int puts(const char* s);
 int fputs(const char* s, FILE* stream);
puts 함수: 문자열을 표준 출력 스트림(stdout)으로 출력하기 위해 사용하는 함수이다. 인자로 전달되는 포인터는 문자열을 가리키고 있어야 한다.
문자열을 출력한 다음에 자동으로 줄을 바꿔준다.

fputs함수 : 문자열을 표준 출력 스트림(stdout)으로 출력하기 위해 사용하는 함수이다. 인자로 전달되는 포인터는 문자열을 가리키고 있어야 한다. +.. 문자열을 출력할 스트림을 선택할 수 있다.
문자열을 출력한 다음에 자동으로 줄을 바꿔주지 않는다.

 #include <stdio.h>

int main()
{
 fputs("fputs 함수에 의한 출력, ", stdout);
 fputs("I Love Linux ", stdout);

 fputs("\n", stdout); //한 줄 건너 뛰기 위해서

 puts("fputs 함수에 의한 출력, ");
 puts("I Love Linux ");
}
 



2) 문자열 입력 함수
하나의 문자열을 입력받을 때 일반적으로 사용하는 함수는 gets함수와 fgets함수이다.
 char* gets(char* s);
 char* fgets(char* s, int n, FILE* stream);
◇gets 함수: 문자열을 입력받는 함수이다. 우선 입력받을 문자열을 저장하기 위한 배열은 선언한 다음, 배열의 시작 주소(배열이름이 배열의 시작주소이다)를 인자로 전달하면서 gets 함수를 호출하게 되면 표준 입력 스트림(키보드)로부터 데이터를 입력받는다.
(하지만 이 함수는 자제해야 함. 미리 할당해 놓은 배열의 크기보다도 큰 길이의 문자열이 들어오게 되면 배열의 Overflow가 발생)

◇fgets함수 :gets함수의 잠재적 위험성 때문에 실제 프로그램에서는 fgets함수만을 사용. fgets함수의 두번째 인자 n은 입력받을 수 있는 최대 문자열의 길이를 나타낸다. 따라서 문자열을 입력받을 배열의 길이를 인자로 전달하면, 그 이상의 문자를 읽어들이는 일은 발생하지 않는다. 마지막으로 세 번째 인자 stream은 입력을 받을 스트림을 지정하기 위해 사용된다.

 #include <stdio.h>

int main()
{
 char str[10];

 fputs("문자열을 입력 하세요: ", stdout);
 fgets(str, sizeof(str), stdin);

 fputs("입력된 문자열: ", stdout);
 fputs(str, stdout);

 return 0;
}
 

※주의 : 배열의 길이가 10이기 때문에 fgets함수 호출시 두 번째 인자(n)에도 10을 전달하였음에도 불구하고 총 9개의 문자가 입력된다. 이는 fgets함수가 문자열을 입력받는 함수이기 때문이다. C에서 문자열이 되기 위한 기본조건은 끝에 반드시 NULL 문자가 들어가야 한다.
(즉 fgets 함수는 입력받을 수 있는 최대 문자열의 길이 n을 초과하는 문자열이 입력되는 경우에는 n-1개 까지의 문자만 입력을 받고, 마지막에 NULL 문자를 삽입해 준다.)


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

열거형(enum) 자료형  (0) 2011.03.01
문자열 처리함수  (0) 2011.03.01
배열포인터  (0) 2011.02.27
포인터와 const키워드  (0) 2011.02.26
scanf 함수 호출 시 &를 붙이는 이유  (0) 2011.02.26
Posted by Triany