선언과초기화 (DCL)
Post on 03-Jan-2016
74 Views
Preview:
DESCRIPTION
Transcript
선언과초기화(DCL)
사이버보안학과 김현성
2/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는
심볼릭 상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록
정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t
로 정의하라
3/88
제안 DCL10-C 가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자
간의 약속이 지켜져야 한다 DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다 DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라 DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의
매개변수로 사용할 때는 const 로 정의하라 DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에
대해서는 어떤 가정도 하지 마라 DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로
선언하라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라 DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라 DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
4/88
5/88
제안 DCL00-C 변 하 지 않 는 객 체 는 const 로
보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭
상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
DCL00-C 부적절한 코드 예
float pi = 3.14159f;float degrees;float radians;/* ... */radians = degrees * pi / 180;
6/88
=> pi 가 수정되지 못하도록 보호되어야함
=> pi=3.14159f;
변하지 않는 객체는 const 로 보장해둬라
DCL00-C 해결방법
const float pi = 3.14159f;float degrees;float radians;/* ... */radians = degrees * pi / 180;
7/88
변하지 않는 객체는 const 로 보장해둬라
8/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라
DCL01-C 내 부 스 코 프 에 서 변 수 이 름 을 재사용하지 마라
DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭
상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
개념적 변수 스코프 룰
전역변수가 사용될 수 있는 범위 내에서 어떤 변수든 중복해서 전역 변수 이름을 사용하면 안된다
어떤 블록 안에서 이미 사용되고 있는 변수와 동일한 이름으로 다른 블록에서 선언하면 안된다
9/88
내부 스코프에서 변수 이름을 재사용하지 마라
DCL01-C 부적절한 코드 예char msg[100];
void report_error(const char *error_msg){char msg[80];/* ... */strncpy(msg, error_msg, sizeof(msg));return;
}int main(void){
char error_msg[80];/* ... */report_error(error_msg);/* ... */
}
10/88
내부 스코프에서 변수 이름을 재사용하지 마라
char msg[80];
char msg[100];
strncpy(msg, error_msg, sizeof(msg));
=> 의도하지 않은 값이 복사됨 , 버퍼오버플로우
DCL01-C 해결방법char system_msg[100];
void report_error(const char *error_msg){ char default_msg[80]; /* ... */ if (error_msg) strncpy(system_msg, error_msg, sizeof(system_msg)); else strncpy(system_msg, default_msg, sizeof(system_msg)); return;}int main(void){
char error_msg[80];/* ... */report_error(error_msg);/* ... */
}
11/88
내부 스코프에서 변수 이름을 재사용하지 마라
12/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라
DCL02-C 시 각 적 으 로 구 별 되 는 식 별 자 를 사용하라
DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭
상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
비슷해 보이는 식별자
1( 하나 ) 과 l( 소문자 엘 ) 0( 영 ) 과 O( 대문자 O) 2( 둘 ) 와 Z( 대문자 Z) 5( 다섯 ) 와 S( 대문자 S) 8( 여덟 ) 과 B( 대문자 B)
13/88
시각적으로 구별되는 식별자를 사용하라
14/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라
DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라
DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭
상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
어썰션 (assert)
assert() 는 소프트웨어 결점을 찾아 제거하는데 사용되는 진단도구– If(index<0||index>=size) {
printf(“ 배열 인덱스 범위 오류” ); }– assert(index>=0&&index<size, “ 배열 인덱스 범위 오
류” );
assert() 는 인자값이 0 이면 메시지 출력– assert((index>=0&&index<size), ” 배열 인덱스 범위 오류” );
15/88
상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라
DCL03-C 부적절한 코드 예
struct timer{unit8_t MODE;unit32_t DATA;unit32_t COUNT;
};int func(void) {
assert(offsetof(timer, DATA)==4);}
16/88
상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라
=> func() 가 호출되어야만 assert 실행됨
<= offsetof(n,a)n 구조체의 a 멤버의 바이트 반환
DCL03-C 해결방법
struct timer{unit8_t MODE;unit32_t DATA;unit32_t COUNT;
};#if(assert(offsetof(timer, DATA) !=4))
#error “DATA must be at offset 4”#endif
17/88
상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라
=> error 지시자 사용시 컴파일타임에 어썰션 평가
18/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라
DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는
심볼릭 상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록
정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
DCL04-C 부적절한 코드 예
char *src = 0, c = 0;
19/88
한 번에 여러 변수를 선언하지 마라
=> char *src, char c=> char *src, char *c
DCL04-C 해결방법
char *src;char *c;
20/88
=> 개별 행으로 변수를 선언
한 번에 여러 변수를 선언하지 마라
21/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라
DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라
DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭 상수를 사용하라
DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
DCL05-C 부적절한 코드 예
void (*signal(int, void(*) (int))) (int);
22/88
=> signal() 함수 선언은 이해하기 힘듦
코드의 가독성을 높이기 위해 타입 정의를 사용하라
DCL05-C 해결방법
typedef void (*SighandlerType) (int signum);extern SighandlerType signal(
int signum,SighandlerType handler
);
23/88
코드의 가독성을 높이기 위해 타입 정의를 사용하라
<= extern 다른 소스코드 .c에서변수나 함수를 현재파일에서 접근하거나 호출할 때 사용
24/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라
DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭 상수를 사용하라
DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록
정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
상수
정수형 상수– 10– 0x1C
부동소수점 상수– 1.0– 6.022e+23
문자상수– ‘a’– ‘\x10’
25/88
프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭 상수를 사용하라
문자 리터럴– “hello, world”– “\n”
<= 심볼릭 상수를 통해 적절한 이름을 붙여 코드의 명확성을 제시하는게 좋음<= const or 열거형 상수 or 객체형 매크로
상수 지정
const – const unsigned int buffer_size = 256;– 컴파일 타임에 정수형 상수가 필요할 때 사용 불가
열거형 상수– enum { max = 15 }; int a[max];
객체형 매크로– #define buffer_size 256
26/88
프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭 상수를 사용하라
DCL06-C 부적절한 코드 예
/* ... */if(age >= 18){
/* 작업 진행 */}else {
/* 다른 작업 진행 */}/* ... */
27/88
프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭 상수를 사용하라
=> 정수 리터럴 18 의 의미가 모호함
18
DCL06-C 해결방법
enum { ADULT_AGE=18 };/* ... */if(age >= ADULT_AGE){
/* 작업 진행 */}else {
/* 다른 작업 진행 */}/* ... */
28/88
프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭 상수를 사용하라
29/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭
상수를 사용하라
DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라
DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로
정의하라
DCL07-C 부적절한 코드 예
int max(a, b)int a, b;{
return a>b ? a : b;}
30/88
함수 선언 시 적절한 타입 정보를 포함시켜라
=> 매개변수와 변수 선언을 별개로 가짐
DCL07-C 해결방법
int max(int a, int b){
return a>b ? a : b;}
31/88
함수 선언 시 적절한 타입 정보를 포함시켜라
32/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭
상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라
DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라
DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로 정의하라
DCL08-C 부적절한 코드 예
코 드 에 서 OUT_STR_LEN 이 항 상 IN_STR_LEN 보다 두개 커야 하는 관계
enum { IN_STR_LEN=18, OUT_STR_LEN=20 };
33/88
상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라
DCL08-C 해결방법
enum { IN_STR_LEN=18, OUT_STR_LEN=IN_STR_LEN+2 };
34/88
상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라
35/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는 심볼릭
상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록 정의하라
DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로 정의하라
에러코드 함수 반환 타입
errno 를 반 환 하 는 많 은 함수가 반환 타입을 int 로 선언하거나 에러 상태 값을 반환
errno_t 타 입 은 errno에서 찾을 수 있는 값들을 갖고 있는 객체의 타입으로 사용되어야 함
36/88
errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로 정의하라
errno: 0 message: Successerrno: 1 message: Operation not permittederrno: 2 message: No such file or directoryerrno: 3 message: No such processerrno: 4 message: Interrupted system callerrno: 5 message: Input/output errorerrno: 6 message: No such device or address…errno: 125 message: Operation canceled
DCL09-C 부적절한 코드 예enum { NO_FILE_POS_VALUES = 3 };int operator(FILE *file,int *width,int *height,int *data_offset){
int file_w;int file_h;int file_o;fpos_t offset;
if(file==NULL) {return EINVAL;}errno=0;if(fgetpos(file, &offset)!=0) {return errno;}if(fscanf(file, “%i %i %i”, &file_w, &file_h, &file_o)
!= NO_FILE_POS_VALUES){ return EIO;}
…
37/88
errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로 정의하라
=> 반환형 int not errno_t 형
int
EINVAL
errno
EIO
DCL09-C 해결방법#include <errno.h>enum { NO_FILE_POS_VALUES = 3 };errno_t operator(FILE *file,int *width,int *height,int *data_offset){
int file_w; int file_h; int file_o; fpos_t offset;
if(file==NULL) {return EINVAL;}errno=0;if(fgetpos(file, &offset)!=0) {return errno;}if(fscanf(file, “%i %i %i”, &file_w, &file_h, &file_o)
!= NO_FILE_POS_VALUES){ return EIO;}
…
38/88
errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t 로 정의하라
39/88
제안 DCL10-C 가변 인자를 가진 함수에서는
함수 작성자와 함수 사용자 간의 약속이 지켜져야 한다
DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다 DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라 DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의
매개변수로 사용할 때는 const 로 정의하라 DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에
대해서는 어떤 가정도 하지 마라 DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로
선언하라
가변 인자 함수 va_list
원래 C 함수들은 고정된 개수의 인수들을 취함 . '가변인자 함수 ' 는 함수가 호출 될 때 마다 인수의 개수를 변경 가능
가변인자 함수를 사용하기 위해서는 'stdarg.h' 헤더 파일이 필요
va_list 형으로 선언– va_start 를 사용해서 va_list 형의 포인터 변수를
인수로써 초기화– va_arg 를 호출함으로써 가변인수들을 엑세스 – va_end 를 호출해서 포인터 변수인 인수를 끝냈음을
알림40/88
가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자 간의 약속이 지켜져야 한다
DCL10-C 부적절한 코드 예enum { va_eol = -1 };
unsigned int average(int first, …){unsigned int count = 0;unsigned int sum = 0;int i = first;va_list args;va_start(args, first);while(i != va_eol){sum += i;count++;i = va_arg(args, int);}va_end(args);return(count ? (sum / count) : 0);
}
41/88
가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자 간의 약속이 지켜져야 한다
=> 호출average(1, 3, 6, 4, 1);
=> 종료값 -1 을만날 수 없어 스택에서 값을 계속 이용
DCL10-C 해결방법
42/88
가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자 간의 약속이 지켜져야 한다
enum { va_eol = -1 };
unsigned int average(int first, …){unsigned int count = 0;unsigned int sum = 0;int i = first;va_list args;va_start(args, first);while(i != va_eol){sum += I;count++;i = va_arg(args, int);}va_end(args);return(count ? (sum / count) : 0);
}
=> 호출시average(1, 3, 6, 4, 1, -1);
43/88
제안 DCL10-C 가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자
간의 약속이 지켜져야 한다
DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다
DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라 DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의
매개변수로 사용할 때는 const 로 정의하라 DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에
대해서는 어떤 가정도 하지 마라 DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로
선언하라
가변 인자 함수
가변 인자 함수의 인자 – 정수형 인자의 경우 int 보다 작은 타입의
인자는 int 로 승계되고 , 그렇지 않은 경우는 unsigned int(4) 로 승계됨
– float 타입의 인자는 double(8) 로 승계됨
44/88
가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다
DCL11-C 부적절한 코드 예
const char *error_msg=“Error occurred”;/* ... */printf(“%s:%d”, 15, error_msg);
45/88
가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다
=> 인자의 순서불일치 오류
=> printf() 함수는 가변인자 함수로 구현15: Error occurred
DCL11-C 해결방법
const char *error_msg=“Error occurred”;/* ... */printf(“%d:%s”, 15, error_msg);
46/88
가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다
47/88
제안 DCL10-C 가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자
간의 약속이 지켜져야 한다 DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다
DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라
DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의 매개변수로 사용할 때는 const 로 정의하라
DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에 대해서는 어떤 가정도 하지 마라
DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로 선언하라
DCL12-C 부적절한 코드 예
struct string_mx{size_t size;size_t maxsize;unsigned char strtype;char *cstr;
}typedef struct string_mx * string_m;/* 함수선언 */extern errno_t strcpy_m(string_m s1, const string_m s2);extern errno_t strcat_m(string_m s1, const string_m s2);/* 기타 */
48/88
불투명한 타입을 사용해 추상 데이터 타입을 구현하라
=> string_mx 는CERT 라이브러리string_m.h 에 정의( 사용자에게 멤버노출 )정보은닉 , 데이터캡슐화제공불가
DCL12-C 해결방법
string_mx 의 데이터 타입이 외부에서 보이지 않도록 private 으로 재구현
=> 두 개 의 헤 더 파 일 생성 ( 하 나 는 외부노출 , 하나는 관리용 내부 파일 )
외부노출 파일 (string_mx 구조체는 내부파일에 제시 )struct string_mx;typedef struct string_mx *string_m;
49/88
불투명한 타입을 사용해 추상 데이터 타입을 구현하라
50/88
제안 DCL10-C 가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자
간의 약속이 지켜져야 한다 DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다 DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라
DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의 매개변수로 사용할 때는 const 로 정의하라
DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에 대해서는 어떤 가정도 하지 마라
DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로 선언하라
DCL13-C 부적절한 코드 예
void foo(int *x){if (x != NULL) {
*x = 3; }/* ... */
}
51/88
함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의 매개변수로 사용할 때는 const 로 정의하라
void foo(const int *x){if (x != NULL) {
*x = 3; }/* ... */
}
<= Error!!!
DCL13-C 해결방법
void foo(const int *x){if (x != NULL) {
printf(“Value is %d\n”, *x); }/* ... */
}
52/88
함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의 매개변수로 사용할 때는 const 로 정의하라
=> 값에 대한 변경 없을때만 const 사용
53/88
제안 DCL10-C 가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자
간의 약속이 지켜져야 한다 DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다 DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라 DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의
매개변수로 사용할 때는 const 로 정의하라
DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에 대해서는 어떤 가정도 하지 마라
DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로 선언하라
DCL14-C 부적절한 코드 예
/* init.c 소스파일 */int init(void) {
static int c = 0;return c++;
}
/* file_a.c 소스파일 */int a = init();
54/88
여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에 대해서는 어떤 가정도 하지 마라
=> a=0, b=1 or a=1, b=0=> a=0, b=0
/* file_b.c 소스파일 */int b = init();
DCL14-C 해결방법
/* init.c 소스파일 */int init(void) {
static int c = 0;return c++;
}
/* ... */int a = init();int b = init();
55/88
여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에 대해서는 어떤 가정도 하지 마라
/* init.h 소스파일 */extern int a;extern int b;
56/88
제안 DCL10-C 가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자
간의 약속이 지켜져야 한다 DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다 DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라 DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의
매개변수로 사용할 때는 const 로 정의하라 DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에
대해서는 어떤 가정도 하지 마라
DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로 선언하라
DCL15-C 부적절한 코드 예
enum { MAX = 100 }int helper(int i){
/* i 로 특정한 연산을 수행 */}
int main(void){size_t I;int out[MAX];for (i=0; i<MAX; i++)
out[i] = helper(i);/* ... */
}57/88
현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로 선언하라
=> helper() 는 main() 함 수 외 부 에 서 사용가능
helper(int i)
helper(i)
DCL15-C 해결방법
enum { MAX = 100 }static int helper(int i){
/* i 로 특정한 연산을 수행 */}
int main(void){size_t i;int out[MAX];for (i=0; i<MAX; i++)
out[i] = helper(i);/* ... */
}58/88
현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로 선언하라
59/88
제안 DCL00-C 변하지 않는 객체는 const 로 보장해둬라 DCL01-C 내부 스코프에서 변수 이름을 재사용하지 마라 DCL02-C 시각적으로 구별되는 식별자를 사용하라 DCL03-C 상수 수식의 값을 테스트할 때 정적 어썰션을 사용하라 DCL04-C 한 번에 여러 변수를 선언하지 마라 DCL05-C 코드의 가독성을 높이기 위해 타입 정의를 사용하라 DCL06-C 프로그램 로직상의 고정적인 값을 나타낼 때는 의미 있는
심볼릭 상수를 사용하라 DCL07-C 함수 선언 시 적절한 타입 정보를 포함시켜라 DCL08-C 상수 정의에서는 상수 간의 관계가 적절하게 나타나도록
정의하라 DCL09-C errno 에러 코드를 반환하는 함수의 반환 타입을 errno_t
로 정의하라
60/88
제안 DCL10-C 가변 인자를 가진 함수에서는 함수 작성자와 함수 사용자
간의 약속이 지켜져야 한다 DCL11-C 가변 인자 함수와 연관된 타입 문제를 파악하고 있어야 한다 DCL12-C 불투명한 타입을 사용해 추상 데이터 타입을 구현하라 DCL13-C 함수에 의해 바뀌지 않을 값에 대한 포인터를 함수의
매개변수로 사용할 때는 const 로 정의하라 DCL14-C 여러 컴파일 단위를 거치는 전역 변수 초기화의 순서에
대해서는 어떤 가정도 하지 마라 DCL15-C 현재 범위를 넘어서까지 사용되지 않을 객체는 static 으로
선언하라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라 DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라 DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
61/88
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라
DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라 DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라 DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
62/88
DCL30-C 부적절한 코드 예const char *p;void dont_do_this(void){
const char str[] = “This will change”;p=str;/* ... */
}void innocuous(void){
const char str[] = “Surprise, surprise”;}/* ... */dont_do_this();innocuous();
63/88=> p 의 메모리는 dont_do_this후 삭제됨
=> p 에 “ This will change” 할당
객체를 선언할 때 적절한 지속공간을 지정하라
DCL30-C 해결방법
void this_is_OK(void){const char str[] = “Everything OK”;const char *p=str;/* ... */
}/* p 는 문자열 str 의 스코프 밖에서 접근할 수 없다 .*/
64/88
객체를 선언할 때 적절한 지속공간을 지정하라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라
DCL31-C 식별자를 사용하기 전에 먼저 선언하라
DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라 DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라 DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
65/88
변수 선언
C90– 변수와 함수에 대해 암시적 타입을 허용– 생략시 signed int 로 지정됨– 암시적 선언으로 타입 체크가 느슨해짐
C99– 암시적 함수 선언 금지– 컴파일러가 C99 를 지원하는게 없어서 암시적 선언을 허용
66/88
식별자를 사용하기 전에 먼저 선언하라
DCL31-C 부적절한 코드 예int main(void) {
int c = foo();printf(“%d\n”, c);return 0;
}
int foo(int a) {return a;
}
67/88
식별자를 사용하기 전에 먼저 선언하라
=> main() 함수에서 foo() 호출전 명백한 프로토타입이 제시되어야 함
foo()
DCL31-C 해결방법int foo(int);int main(void) {
int c = foo();printf(“%d\n”, c);return 0;
}
int foo(int a) {return a;
}
68/88
식별자를 사용하기 전에 먼저 선언하라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라
DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라
DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와 목적 포인터가 동일한 객체를 참조하지 않게 하라
DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라 DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
69/88
식별자 룰
두 스코프에서 서로 참조되는 식별자가 있는 경우 이름 구별
다른 스코프 영역이라면 중복된 이름의 식별자 이용 가능
식별자의 유일성 보장을 위한 글자수 – 내부 식별자나 매크로 이름으로 63 개의
문자– 외부 식별자로 31 개의 문자
70/88
서로에게 보이는 식별자가 유일한지를 보장하라
DCL32-C 부적절한 코드 예
extern int *global_symbol_definition_lookup_table_a;extern int *global_symbol_definition_lookup_table_b;
71/88
=> 첫 32 개 문자가 동일해 유일성 보장 X
서로에게 보이는 식별자가 유일한지를 보장하라
DCL32-C 해결방법
extern int *a_global_symbol_definition_lookup_table;extern int *b_global_symbol_definition_lookup_table;
72/88
=> 첫 31 개 글자내에서 구별 가능하도록
서로에게 보이는 식별자가 유일한지를 보장하라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라
DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와 목적 포인터가 동일한 객체를 참조하지 않게 하라
DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라 DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
73/88
restrict
포인터 선언에 사용할 수 있는 한정자 포인터의 라이프사이클 동안 한 포인터
변수만 그 변수가 참조하는 메모리에 접근할 수 있음
Aliasing 을 방지함
74/88
함수 인자에서 restrict 로 지정된 소스 포인터와 목적 포인터가 동일한 객체를 참조하지 않게 하라
DCL33-C 부적절한 코드 예
char str[] = “test string”;char *ptr1 = str;char *ptr2;ptr2 = ptr1 + 3;memcpy(ptr2, prt1, 6);
75/88
함수 인자에서 restrict 로 지정된 소스 포인터와 목적 포인터가 동일한 객체를 참조하지 않게 하라
=> ptr1 과 ptr2 가 참조하는 영역이 겹침memcpy() 함수후 결과 예측 불가
ptr1
ptr2
DCL33-C 해결방법
char str[] = “test string”;restrict char *ptr1 = str;char *ptr2;ptr2 = ptr1 + 3;memmove(ptr2, prt1, 6);
76/88
=> memcpy() 대신 memmove() 대체
함수 인자에서 restrict 로 지정된 소스 포인터와 목적 포인터가 동일한 객체를 참조하지 않게 하라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라
DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라
DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지 마라
DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
77/88
volatile
“ 변덕스러운” 의미 변 수 가 여 러 요 인 에 의 해 변 경 될
가능성이 있는 경우 컴파일러로 하여금 최적화 금지 요청하는 경우 사용
비동기 시그널 처리가 가능하게 함
78/88
캐시될 수 없는 데이터에는 volatile 을 사용하라
DCL34-C 부적절한 코드 예
#include <signal.h>sig_atomic_t i;void handler(int signum){
i = 0;}int main(void){
i = 1;signal(SIGINT, handler);while(i){
/* 내부작업 */}return 0;
}
79/88
캐시될 수 없는 데이터에는 volatile 을 사용하라
=> i 값이 캐시된다면while 을 통해 무한루프
=> 인터럽트 있음 (i=0) 없음 (i=1)
DCL34-C 해결방법
#include <signal.h>volatile sig_atomic_t i;void handler(int signum){
i = 0;}int main(void){
i = 1;signal(SIGINT, handler);while(i){
/* 내부작업 */}return 0;
}
80/88
=> i 가 while 루 프 들어갈때 , 시그널 핸들러 호출시 원래 주소 접근 보장
캐시될 수 없는 데이터에는 volatile 을 사용하라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라 DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라
DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지 마라
DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
81/88
DCL35-C 부적절한 코드 예
/* my_function 은 반환 타입이 void 다 */static void my_function(int a){
/* ... */return;
}int main(void){
int x;int (*new_function)(int a) = my_function;x = (*new_function)(10); return 0;
}
82/88
=> 반환값이 void 형인 my_function 에서 결과값 x 처리
함수 정의와 맞지 않는 타입으로 함수를 변환하지 마라
x
DCL35-C 해결방법
/* my_function 은 반환 타입이 int 다 */static int my_function(int a){
/* ... */return a;
}int main(void){
int x;int (*new_function)(int a) = my_function;x = (*new_function)(10); return 0;
}
83/88
<= 함수의 매개변수 및 반환형을 통일해 문제 해결
함수 정의와 맞지 않는 타입으로 함수를 변환하지 마라
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라 DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라
DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
84/88
식별자 분류
외부링크 : 외부로 링크된 식별자는 전체 프 로 그 램 에 서 , 즉 모 든 컴 파 일 단 위 나 라이브러리에서 동일한 객체나 함수를 나타냄
내부링크 : 주어진 컴파일 단위에서 동일한 객체나 함수를 나타내도록 되어있는 식별자임
링 크 없 음 : 식 별 자 에 링 크 가 없 다 면 이 식별자를 사용한 경우 새로운 변수나 타입이 선언됨
85/88
링크 분류에서 충돌되는 식별자를 선언하지 마라
DCL36-C 부적절한 코드 예
int i1 = 10;static int i2 = 20;extern int i3 = 30;int i4;static int i5;
int i1;int i2;int i3;int i4;int i5;
int main(void) {/* ... */
}
86/88
/* 정의 , 외부링크 */
링크 분류에서 충돌되는 식별자를 선언하지 마라
/* 정의 , 내부링크 *//* 정의 , 외부링크 *//* 임시정의 , 외부링크 *//* 임시정의 , 내부링크 */
/* 유효한 임시정의 *//* 유효하지 않음 , 이전정의와 불일치 *//* 유효한 임시정의 *//* 유효한 임시정의 *//* 유효하지 않음 , 이전정의와 불일치 */
DCL36-C 해결방법
int i1 = 10;static int i2 = 20;extern int i3 = 30;int i4;static int i5;
int main(void) {/* ... */
}
87/88
링크 분류에서 충돌되는 식별자를 선언하지 마라
/* 정의 , 외부링크 *//* 정의 , 내부링크 *//* 정의 , 외부링크 *//* 임시정의 , 외부링크 *//* 임시정의 , 내부링크 */
규칙
DCL30-C 객체를 선언할 때 적절한 지속공간을 지정하라 DCL31-C 식별자를 사용하기 전에 먼저 선언하라 DCL32-C 서로에게 보이는 식별자가 유일한지를 보장하라 DCL33-C 함수 인자에서 restrict 로 지정된 소스 포인터와
목적 포인터가 동일한 객체를 참조하지 않게 하라 DCL34-C 캐시될 수 없는 데이터에는 volatile 을 사용하라 DCL35-C 함수 정의와 맞지 않는 타입으로 함수를 변환하지
마라 DCL36-C 링크 분류에서 충돌되는 식별자를 선언하지 마라
88/88
top related