2-1 코딩 스타일의 이해
1. 코딩(Coding)
일반적으로 프로그래밍 언어를 사용하여 원시 코드 또는 소스 코드를 작성하는 행위를 코딩이라고 한다.
2. 프로그래밍과 코딩(Programming and Coding)
코딩과 프로그래밍은 유사한 개념으로 사용되지만 엄밀히 이야기하면 다음과 같다.
- 프로그래밍 - 프로그램의 논리를 설계하는것
- 코딩 - 프로그램의 논리에 따라 특정 언어를 사용하여 구현
- 개발 기간의 지연 방지
- 유지 보수에 대한 편리성
- 견고한 프로그램의 구현
- K&R
- GNU
- BSD
코드 수를 절약하며 한눈에 많은 코드를 볼 수 있고, 수평으로 많은 코드를 작성할 수 있다.
그리고 이는 버그의 위험이 될 수 있다.
해결 방법 - 한 줄에 한 문장만 기술한다.
#include <stdio.h>
2-3 서로 의미가 있는 코드는 단락으로 묶어라
1. 좋지 않은 코드
다음의 코드는 가독성을 떨어트리고 유지 보수하기도 어렵다.
#include <stdio.h>
#define TRUE (1)
#define FALSE (2)
#define STACK_SIZE (10)
typedef struct _Stack{
int arr[STACK_SIZE];
int top;
}Stack;
void init_stakc(Stack* stack){ stack->top = 0; }
int is_full(const Stack* stack) { return stack->top = STACK_SIZE; }
int is_empty(const Stack *stack) { return stack->top = 0; }
int push(Stack* stack, int data){
if(is_full(stack))
return -1;
stack->arr[(stack->top)++] = data;
return 0;
}
int pop(Stack* stack, int* data){
if(is_empty(stack) || data == NULL)
return -1;
*data = stack->arr[--(stack->top)];
return 0;
}
int main(){
Stack stack;
init_stack(&stack);
int i;
for(i=0; i < 5; i++){
push(&stack, i + 1);
}
for(i=0; i < 5; i++){
int data;
pop(&stack, &data);
printf("%d\n", data);
}
return 0;
}
해결 방법 - 서로 의미가 있는 코드는 다음과 같이 단락으로 묶는다.
#include <stdio.h>
#define TRUE (1)
#define FALSE (2)
typedef struct _Stack{
#define STACK_SIZE (10)
int arr[STACK_SIZE];
int top;
}Stack;
void init_stakc(Stack* stack) {
stack->top = 0;
}
int is_full(const Stack* stack) {
return stack->top = STACK_SIZE;
}
int is_empty(const Stack *stack) {
return stack->top = 0;
}
int push(Stack* stack, int data){
if(is_full(stack))
return -1;
stack->arr[(stack->top)++] = data;
return 0;
}
int pop(Stack* stack, int* data){
if(is_empty(stack) || data == NULL)
return -1;
*data = stack->arr[--(stack->top)];
return 0;
}
int main(){
Stack stack;
init_stack(&stack);
int i;
for(i=0; i < 5; i++){
push(&stack, i + 1);
}
for(i=0; i < 5; i++){
int data;
pop(&stack, &data);
printf("%d\n", data);
}
return 0;
}
2-4 연산자의 앞과 뒤에 공백을 두라
1. 좋지 않은 코드 - 코드의 가독성이 떨어진다
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node{
int data;
struct _Node* next;
} Node;
void insert_front(Node **head,int data){
Node *node =(Node*)malloc(sizeof(Node));
node->data=data;
node->next=*head;
*head=node;
}
void display_list(const Node **head){
system("cls");
printf("[head]");
for(Node *node=*head; node!=NULL; node=node->next)
printf("->[%2d]", node->data);
getchar();
}
int main(){
Node *head=NULL;
display_list(&head);
int i;
for(i=0; i<5; i++){
insert_front(&head, i+1);
display_list(&head);
}
return 0;
}
해결방법 - 연산자의 앞과 뒤에 공백을 추가한다.
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node{
int data;
struct _Node* next;
} Node;
void insert_front(Node **head, int data){
Node *node = (Node*)malloc(sizeof(Node));
node->data = data;
node->next = *head;
*head = node;
}
void display_list(const Node **head){
system("cls");
printf("[head]");
for(Node *node = *head; node != NULL; node = node->next)
printf("->[%2d]", node->data);
getchar();
}
int main(){
Node *head = NULL;
display_list(&head);
int i;
for(i = 0; i < 5; i++){
insert_front(&head, i + 1);
display_list(&head);
}
return 0;
}
2-5 중괄호의 위치를 통일 시켜라
1. 좋지 않은 코드
중괄호의 위치가 제각각이어서 가독성이 떨어진다.
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node{
int data;
struct _Node* next;
} Node;
typedef struct _List { Node* head; } List;
void init_list(List *list) { list->head = NULL; }
void insert_front(Node **head, int data)
{
Node *node = (Node*)malloc(sizeof(Node));
node->data = data;
node->next = *head;
*head = node;
}
void display_list(const Node **head){
system("cls");
printf("[head]");
for(Node *node = *head; node != NULL; node = node->next)
printf("->[%2d]", node->data);
getchar();
}
int main()
{
Node *head = NULL;
display_list(&head);
int i;
for(i = 0; i < 5; i++)
{
insert_front(&head, i + 1);
display_list(&head);
}
return 0;
}
해결 방법 - 중괄호의 위치를 일관되게 사용한다.
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node {
int data;
struct _Node* next;
} Node;
typedef struct _List {
Node* head;
} List;
void init_list(List *list) {
list->head = NULL;
}
void insert_front(Node **head, int data) {
Node *node = (Node*)malloc(sizeof(Node));
node->data = data;
node->next = *head;
*head = node;
}
void display_list(const Node **head) {
system("cls");
printf("[head]");
for(Node *node = *head; node != NULL; node = node->next)
printf("->[%2d]", node->data);
getchar();
}
int main() {
Node *head = NULL;
display_list(&head);
int i;
for(i = 0; i < 5; i++) {
insert_front(&head, i + 1);
display_list(&head);
}
return 0;
}
2-6 변수의 이름에 적절한 접두사를 사용하라
다음은 변수에 관행적으로 사용되는 접두사들이다.
접두사 |
의미 |
arr |
배열(Array) |
b |
불리언(boolean) |
c |
문자(character) |
i |
정수(integer) |
f |
단정도 실수(float) |
d |
배정도 실수(double) |
fd |
파일 기술자(file descriptor) |
fp |
파일 포인터(file pointer) |
h |
핸들(handle) |
p |
일중 포인터(single pointer) |
pp |
이중 포인터(double pointer) |
s |
정적 변수(static variable) |
g |
전역 변수(global variable) |
str |
문자열(string) |
1. 좋지 않은 코드
실수 연산의 결과를 정수 타입의 변수에 저장하고 있다.
#include <stdio.h>
int main(){
double num1 = 0.1;
double num2 = 0.2;
//...
int sum = num1 + num2;
printf("%d\n", sum);
return 0;
}
해결 방법 - 접두사를 사용한다.
#include <stdio.h>
int main(){
double dNum1 = 0.1;
double dNum2 = 0.2;
//...
double dSum = dNum1 + dNum2;
printf("%d\n", dSum);
return 0;
}
2. 좋지 않은 코드
다음 코드는 잘못된 메모리 참조를 수행하고 있다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_name(char **name){
char buf[32];
printf("Input name: ");
scanf("%s", buf);
char* p = malloc(strlen(buf) + 1);
if(p == NULL){
perror("malloc");
return -1;
}
strcpy(p, buf);
name = p;
return 0;
}
int main(){
char *name;
get_name(&name);
printf("-> %s\n", name);
free(name);
return 0;
}
해결 방법 - 포인터 접두사를 사용한다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_name(char **ppName){
char buf[32];
printf("Input name: ");
scanf("%s", buf);
char* p = malloc(strlen(buf) + 1);
if(p == NULL){
perror("malloc");
return -1;
}
strcpy(p, buf);
ppName = p;
return 0;
}
int main(){
char *pName;
get_name(&pName);
printf("-> %s\n", pName);
free(pName);
return 0;
}
3. 좋지 않은 코드
insert_front 함수 내부에서 전역 변수와 동일한 심볼을 사용하고 있다.
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node {
int data;
struct _Node *next;
} Node;
Node *head = NULL;
void insert_front(int data){
Node *node = malloc(sizeof(Node));
node->data = data;
//...
Node *head;
node->next = head;
head = node;
}
Node *remove_front(){
Node* node = head;
head = node->next;
return node;
}
int main(){
int i;
for(i = 0; i < 5; i++)
insert_front(i + 1);
Node *node = remove_front();
free(node);
return 0;
}
해결 방법 - 전역 변수를 식별하기 위한 접두사를 사용한다.
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node {
int data;
struct _Node *next;
} Node;
Node *pHead = NULL;
void insert_front(int data){
Node *node = malloc(sizeof(Node));
node->data = data;
//...
Node *head;
node->next = pHead;
pHead = node;
}
Node *remove_front(){
Node* node = pHead;
pHead = node->next;
return node;
}
int main(){
int i;
for(i = 0; i < 5; i++)
insert_front(i + 1);
Node *node = remove_front();
free(node);
return 0;
}
2-7 함수의 기능을 식별할 수 있도록 접두사를 사용하라
다음은 함수에 관행적으로 사용되는 접두사이다.
접두사 |
의미 |
예 |
get |
어떤 값을 얻어온다 |
get_age |
set |
어떤 값을 저장한다 |
set_age |
is |
어떤 것에 대해 묻는다 |
is_full |
check |
어떤 것에 대해 조사한다 |
check_error |
1. 좋지 않은 코드
다음의 코드에서 함수의 기능을 유추하기 어렵다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int name(char **ppName){
if(ppName == NULL)
return -1;
char buf[32];
printf("Input name : ");
scanf("%s", buf);
char *pName = (char*)malloc(strlen(buf) + 1);
if(pName == NULL){
error("malloc");
return -1;
}
strcpy(pName, buf);
**ppName = pName;
return 0;
}
int main(){
char *pName = NULL;
if(name(&pName) < 0)
return -1;
printf("-> %s\n", pName);
free(pName);
return 0;
}
해결 방법 - 함수의 기능을 식별할 수 있는 접두사를 사용한다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_name(char **ppName){
if(ppName == NULL)
return -1;
char buf[32];
printf("Input name : ");
scanf("%s", buf);
char *pName = (char*)malloc(strlen(buf) + 1);
if(pName == NULL){
error("malloc");
return -1;
}
strcpy(pName, buf);
**ppName = pName;
return 0;
}
int main(){
char *pName = NULL;
if(get_name(&pName) < 0)
return -1;
printf("-> %s\n", pName);
free(pName);
return 0;
}
2-8 이름은 의미 있고 간결하게 작성하라
1. 좋지 않은 코드
선언된 변수가 어떠한 의미를 갖는지 유추하기 어렵다.
#include <stdio.h>
#include <stdlib.h>
int ** create_matrix(int a, int b){
int **c = (int**)malloc(sizeof(int*) * a);
int iterator;
for(iterator = 0; iiterator < a; iterator++)
c[iterator] = (int*)calloc(b, sizeof(int));
return c;
}
int main(){
int **z = create_matrix(2, 3);
int a, b;
for(a = 0; a < 2; a++){
for(b = 0; b < 3; b++)
printf("%2d ", z[a][b]);
printf("\n");
}
free(z);
return 0;
}
해결 방법 - 의미 있는 이름으로 변경한다.
#include <stdio.h>
#include <stdlib.h>
int ** create_matrix(int row, int col){
int **matrix = (int**)malloc(sizeof(int*) * a);
int i;
for(i = 0; i < row; i++)
c[i] = (int*)calloc(col, sizeof(int));
return matrix;
}
int main(){
int **matrix = create_matrix(2, 3);
int a, b;
for(i = 0; i < 2; i++){
for(j = 0; j < 3; j++)
printf("%2d ", matrix[i][j]);
printf("\n");
}
free(matrix);
return 0;
}
2-9 포인터 변수의 선언에서 포인터 기호는 변수 이름에 붙여라
1. 좋지 않은 코드
변수 pTel은 문자에 대한 포인터가 아니라 문자를 저장하는 변수이다.
#include <stdio.h>
int main(){
char* pName, pTel;
pName = 0;
pTel = 0;
//...
return 0;
}
해결 방법 - 포인터 기호를 변수에 붙여 선언한다.
#include <stdio.h>
int main(){
char *pName, pTel;
pName = 0;
pTel = 0;
//...
return 0;
}
2-10 하나의 표현식에는 가급적 하나의 연산만 수행하라
1. 좋지 않은 코드
우선 순위에 대한 잘못된 이해로 프로그램은 제대로 동작하지 않는다.
#include <stdio.h>
int main(){
FILE *fp = fopen("main.c", "rb");
if(fp == NULL){
perror("fopen");
return -1;
}
int ch;
while(ch = fgetc(fp) != EOF)
fputc(ch, stdout);
printf("\n");
fclose(fp);
return 0;
}
해결 방법 - 가급적 하나의 표현식에는 하나의 연산만 수행한다.
#include <stdio.h>
int main(){
FILE *fp = fopen("main.c", "rb");
if(fp == NULL){
perror("fopen");
return -1;
}
int ch = fgetc(fp);
while(ch != EOF){
putchar(ch);
ch = fgetc(fp);
}
printf("\n");
fclose(fp);
return 0;
}
'Software' 카테고리의 다른 글
Secure Cordng C - Declaration (0) | 2018.07.24 |
---|---|
Secure Cordng C - Preprocessor (0) | 2018.07.23 |
Secure Cordng C - 포인터의 개념과 이해 #3 (0) | 2018.07.18 |
Secure Cordng C - 포인터의 개념과 이해 #2 (0) | 2018.07.18 |
Secure Cordng C - 포인터의 개념과 이해 #1 (0) | 2018.07.09 |