태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.
블로그 이미지
하늘을 헤엄치다. revoman

카테고리

분류 전체보기 (176)
Eye (13)
Programming (82)
Unix & Linux (52)
Android (3)
Tool and Tip (13)
시스템 관리 (7)
OPEN SOURCE (2)
XML (1)
WEB (0)
MY PROGRAM (1)
정보관리기술사 기출.. (1)
IT 동향 (1)
Total56,866
Today6
Yesterday34

'coding rules'에 해당되는 글 1건

  1. 2009/09/15 system programming coding rules

Preprocessor

  • 소스 코드의 헤더 파일은 항상 inclusion guard를 포함해야 한다.

Compliant Solution
#ifndef _HEADER_H_
#define _HEADER_H_
/* ... contents of the header */
#endif /* _HEADER_H_ */


  • 소스 코드 및 주석에서 반복되는 ? 를 사용하지 말아야 한다.

Noncompliant Code Example Compliant Solution
size_t i = /* some initial value */;
if (i > 9000) {
   if (puts("Over 9000!??!") == EOF) {
     /* Handle Error */
   }
}
size_t i = /* some initial value */;
/* assignment of i */
if (i > 9000) {
   if (puts("Over 9000!?""?!") == EOF) {
     /* Handle Error */
   }
}

Declarations and Initialization

  • 함수에 의하여 변경되지 않는 parameter를 위한 pointer는 const로 선언한다.

Noncompliant Code Example Compliant Solution
void foo(int * x) {
  if (x != NULL) {
    printf("Value is %d\n", *x);
  }
  /* ... */
}
void foo(const int * x) {
  if (x != NULL) {
    printf("Value is %d\n", *x);
  }
  /* ... */
}


  • 내부에서만 사용되는 함수는 항상 static으로 선언한다.

Noncompliant Code Example Compliant Solution
enum { MAX = 100 };

int helper(int i) {
  /* perform some computation based on i */
}

int main(void) {
  size_t i;
  int out[MAX];

  for (i = 0; i < MAX; i++) {
    out[i] = helper(i);
  }

  /* ... */

}
enum {MAX = 100};

static int helper(int i) {
  /* perform some computation based on i */
}

int main(void) {
  size_t i;
  int out[MAX];

  for (i = 0; i < MAX; i++) {
    out[i] = helper(i);
  }

  /* ... */

}


  • source buff 와 destination buff는 같은 메모리 공간이 되지 않도록 설계한다.

Noncompliant Code Example
char str[]= "test string";
char *ptr1=str;
char *ptr2;

ptr2 = ptr1 + 3;
memcpy(ptr2, ptr1, 6);

Expression

  • 두 structure를 비교할때는 memcmp() 함수를 사용하지 않고 직접 비교한다.

Noncompliant Code Example Compliant Solution
struct my_buf {
  char buff_type;
  size_t size;
  char buffer[50];
};

unsigned int buf_compare(
  const struct my_buf *s1, 
  const struct my_buf *s2) 
{
  if (!memcmp(s1, s2, sizeof(struct my_buf))) {
    return 1;
  }
  return 0;
}

struct my_buf {
  char buff_type;
  size_t size;
  char buffer[50];
};

unsigned int buf_compare(
  const struct my_buf *s1, 
  const struct my_buf *s2) 
{
  if (s1->buff_type != s2->buff_type) return 0;
  if (s1->size != s2->size) return 0;
  if (strcmp(s1->buffer, s2->buffer) != 0) return 0;
  return 1;
}

Integer, Float, Array, String

  • 배열의 길이를 나타내는 parameter는 int 형대신 size_t, ssize_t 형을 사용한다.
    • 32bit 머신과 64bit 머신간의 호환성을 위함

Noncompliant Code Example Compliant Solution
char str = "abc";
int len;

len = strlen(str);
  ...
}
char str = "abc";
size_t len;

len = strlen(str);
  ...


  • atoi() 함수류 대신에 strtol() 함수류를 사용한다.
    • atoi() 함수류는 error를 detect할수 없다.
 atoi: (int)strtol(nptr, (char **)NULL, 10)
 atol: strtol(nptr, (char **)NULL, 10)
 atoll: strtoll(nptr, (char **)NULL, 10)

Noncompliant Code Example Compliant Solution
int si;

if (argc > 1) {
  si = atoi(argv[1]);
}
long sl;
int si;
char *end_ptr;

if (argc > 1) {
  errno = 0;

  sl = strtol(argv[1], &end_ptr, 10);

  if ((sl == LONG_MIN || sl == LONG_MAX) && errno != 0) {
    perror("strtol error");
  }
  else if (end_ptr == argv[1]) {
    if (puts("error encountered during conversion") == EOF) {
      /* Handle error */
    }
  }
  else if (sl > INT_MAX) {
    printf("%ld too large!\n", sl);
  }
  else if (sl < INT_MIN) {
    printf("%ld too small!\n", sl);
  }
  else if ('\0' != *end_ptr) {
    if (puts("extra characters on input line\n") == EOF) {
      /* Handle error */
    }
  }
  else {
    si = (int)sl;
  }
}


  • array의 길이 또는 위치를 입력 받는 함수는 항상 입력받은 값이 valid한지 check 해야 한다.

Noncompliant Code Example Compliant Solution
void func(size_t s) {
  int vla[s];
  /* ... */
}
/* ... */
func(size);
/* ... */
enum { MAX_ARRAY = 1024 };

void func(size_t s) {
  if (s < MAX_ARRAY && s != 0) {
    int vla[s];
    /* ... */
  } else {
    /* Handle error */
  }
}

/* ... */
func(size);
/* ... */
Noncompliant Code Example Compliant Solution
enum { WORKSPACE_SIZE = 256 };

void func(const int src[], size_t len) {
  int dest[WORKSPACE_SIZE];
  memcpy(dest, src, len * sizeof(int));
  /* ... */
}
enum { WORKSPACE_SIZE = 256 };

void func(const int src[], size_t len) {
  int dest[WORKSPACE_SIZE];
  if (len > WORKSPACE_SIZE/sizeof(int)) {
      /* Handle error */
  }
  memcpy(dest, src, sizeof(int)*len);
  /* ... */
}


  • strcpy(), strcat(), sprintf(), .. 등 destination buff의 크기를 검사하지 않는 문자열 함수는 사용하지 않는다.

Noncompliant Code Example Compliant Solution
#define FILE_PATH_MAX 100

char config_path[FILE_PATH_MAX];
char *env_home;

env_home = getenv("HOME");
if (env_home == NULL) {
    return -1;
}

sprintf(config_path, "%s/etc/config.ut", env_home);
#define FILE_PATH_MAX 100

char config_path[FILE_PATH_MAX];
char *env_home;

env_home = getenv("HOME");
if (env_home == NULL) {
    return -1;
}

snprintf(config_path, sizeof(config_path), "%s/etc/config.ut", env_home);


  • strncat(), strncpy() 함수들은 dest buff가 부족할경우 null-terminated 되지 않은 불완전한 문자열을 만들수 있으므로 strlcat(), strlcpy() 함수를 사용한다
    • strlcat(), strlcpy() 함수는 Solaris 8 이상에서만 지원되며, 다른 운영체제에서는 MPF에서 지원한다.

Noncompliant Code Example Compliant Solution
#define STR_MAX 5

char str[STR_MAX];

strncat(str, "0123456789", sizeof(str));
#define STR_MAX 5

char str[STR_MAX];

strlcat(str, "0123456789", sizeof(str));


  • isalpha(), islower(), isupper(), .. 등 isxxx() 류의 함수사용시 입력문자 c는 항상 unsigned char 형으로 cast하여 사용한다.
 int isalnum(int c);
 int isalpha(int c);
 int isascii(int c);
 int isblank(int c);
 int iscntrl(int c);
 int isdigit(int c);
 int isgraph(int c);
 int islower(int c);
 int isprint(int c);
 int ispunct(int c);
 int isspace(int c);
 int isupper(int c);
 int isxdigit(int c);

Noncompliant Code Example Compliant Solution
size_t count_preceding_whitespace(const char *s) {
  const char *t = s;
  size_t length = strlen(s) + 1;

  /* possibly *t < 0 */
  while (isspace(*t) && (t - s < length)) {
    ++t;
  }
  return t - s;
}
size_t count_preceding_whitespace(const char *s) {
  const char *t = s;
  size_t length = strlen(s) + 1;

  while (isspace((unsigned char)*t) && (t - s < length)) {
    ++t;
  }
  return t - s;
}


  • strtok() 함수는 token을 분리하기 위하여 입력 buff의 손상을 가져오기 때문에 항상 복사본으로 작업한다.

Noncompliant Code Example Compliant Solution
char *token;
char *path = getenv("PATH");

token = strtok(path, ":");
puts(token);

while (token = strtok(0, ":")) {
  puts(token);
}

printf("PATH: %s\n", path);
/* PATH is now just "/usr/bin" */
char *token;
const char *path = getenv("PATH");
/* PATH is something like "/usr/bin:/bin:/usr/sbin:/sbin" */

char *copy = (char *)malloc(strlen(path) + 1);
if (copy == NULL) {
  /* handle error */
}
strcpy(copy, path);
token = strtok(copy, ":");
puts(token);

while (token = strtok(0, ":")) {
  puts(token);
}

free(copy);
copy = NULL;

printf("PATH: %s\n", path);
/* PATH is still "/usr/bin:/bin:/usr/sbin:/sbin" */


  • strlen() 함수는 결과 값에 null-terminating 문자를 포함하지 않기때문에 주의해서 사용해야 한다.

Noncompliant Code Example Compliant Solution
int main(int argc, char *argv[]) {
  /* ... */
  char prog_name[128];
  strcpy(prog_name, argv[0]);
  /* ... */
}
int main(int argc, char *argv[]) {
  /* ... */
  char * prog_name;
  size_t prog_size;

  prog_size = strlen(argv[0])+1;
  prog_name = (char *)malloc(prog_size);

  if (prog_name != NULL) {
    if (strlcpy(prog_name, argv[0]), prog_size) {
      /* Handle strcpy_s() error */
    }
  }
  else {

    /* Couldn't get the memory - recover */
  }
  /* ... */
}

Memory Management

  • 최대한 동적할당된 메모리는 같은 모듈에서 해제시켜준다.

Noncompliant Code Example Compliant Solution
enum { MIN_SIZE_ALLOWED = 32 };

int verify_size(char *list, size_t size) {
  if (size < MIN_SIZE_ALLOWED) {
    /* Handle Error Condition */
    free(list);
    return -1;
  }
  return 0;
}

void process_list(size_t number) {
  char *list = (char *)malloc(number);
  if (list == NULL) {
    /* Handle Allocation Error */
  }

  if (verify_size(list, number) == -1) {
      free(list);
      return;
  }

  /* Continue Processing list */

  free(list);
}
enum { MIN_SIZE_ALLOWED = 32 };

int verify_size(const char *list, size_t size) {
  if (size < MIN_SIZE_ALLOWED) {
    /* Handle Error Condition */
    return -1;
  }
  return 0;
}

void process_list(size_t number) {
  char *list = (char *)malloc(number);

  if (list == NULL) {
    /* Handle Allocation Error */
  }

  if (verify_size(list, number) == -1) {
      free(list);
      return;
  }

  /* Continue Processing list */

  free(list);
}


  • 자원을 사용한 후의 변수는 즉시 초기화 시킨다. (free(), close(), fclose() ...)

Noncompliant Code Example Compliant Solution
char *message;
int message_type;

/* Initialize message and message_type */

if (message_type == value_1) {
  /* Process message type 1 */
  free(message);
}
/* ...*/
if (message_type == value_2) {
   /* Process message type 2 */
  free(message);
}
char *message;
int message_type;

/* initialize message and message_type */

if (message_type == value_1) {
  /* Process message type 1 */
  free(message);
  message = NULL;
}
/* ...*/
if (message_type == value_2) {
  /* Process message type 2 */
  free(message);
  message = NULL;
}


  • malloc(), calloc(), realloc() 함수 사용시 입력 size가 0이 되지 않도록 보장해야 한다.
    • size가 0 일경우 함수의 행동은 정해져 있지 않으며, 구현에 따라 다르다.

Noncompliant Code Example Compliant Solution
size_t size;

/* initialize size, possibly by user-controlled input */

int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
else {
/* Continue processing list */
}
size_t size;

/* initialize size, possibly by user-controlled input */

if (size == 0) {
  /* Handle error */
}
int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
/* Continue processing list */


  • rewind() 함수는 에러를 리턴하지 않으므로, fseek() 함수를 사용한다.

Noncompliant Code Example Compliant Solution
char *file_name;
FILE *fp;

/* initialize file_name */

fp = fopen(file_name, "r");
if (fp == NULL) {
  /* Handle open error */
}

/* read data */

rewind(fp);

/* continue */
char *file_name;
FILE *fp;

/* initialize file_name */

fp = fopen(file_name, "r");
if (fp == NULL) {
  /* Handle open error */
}

/* read data */

if (fseek(fp, 0L, SEEK_SET) != 0) {
  /* Handle repositioning error */
}

/* continue */


Signal

  • signal 함수를 등록하기 위해 signal() 함수 대신 sigaction() 함수를 사용한다.
    • signal() 함수는 persistant하게 signal handler를 운용하기 위해서는 signal handler안에서 signal을 재등록해야한다.
    • sigaction() 함수는 struct sigaction 구조체 값을 이용하여 다양한 signal 처리가 가능하다.
    • MPF에서는 mpsignal() 함수가 sigaction() 함수를 이용해 구현되었으므로, 이 함수를 사용한다.


  • signal handler안에서는 asynchronous-safe 함수만을 사용한다.

Image:Asynchronous-signal-safe functions.jpg

Error

  • 리턴 값을 가지는 모든 함수는 error 처리를 해야 한다.


Log Format

  • 32bit/64bit 호환성을 위하여 pid_t, pthread_t, thread_t, size_t, ssize_t, socklen_t 형을 로그에 쓸경우 long type으로 변환한다.
    • pid_t, pthread_t, size_t, socklen_t: (unsigned long int)
    • ssize_t: (long int)
    • 예) LOG_SVC("%s:: ccm_forward_thr exit, TID=%lu\n", __func__, (unsigned long int)pthread_self());
Posted by revoman

최근에 달린 댓글

최근에 받은 트랙백

글 보관함