출처 : http://blog.naver.com/PostView.nhn?blogId=dolicom&logNo=10096312448
보통 리눅스 커널을 디버깅 하려면 쉽게 log 메세지를 이용할 수 있다. 이럴 때는 printk 함수를 사용하면 되는데 디버깅이 끝나면 제거 하면 된다.
#ifdef DEBUG
#define DPRINTF(fmt,args,...) printk(##args)
#else
#define DPRINTF
#endif
이렇게 하면
DPRINTF을 골라서 쉽게 제거할 수 있다.
예를 들어 특정 부분만을 디버깅 할 때만 printf 한다면
#include <stdio.h>
#define DEBUG
#ifdef DEBUG
#define DPRINTF(fmt,args,...) printf( "%s:%s:%d: " fmt, __FILE__, __FUNCTION__, __LINE__, ##args)
#else
#define DPRINTF - 코드내의 이 함수를 제거 하여 출력하지 않는다.
#endif
int main( int argc, char *argv[])
{
int i = 0;
if (argc < 2) {
DPRINTF( "argc=%d\n", argc);
} else {
DPRINTF( "argc=%d,argv1=%s\n", argc, argv[1]);
}
printf("파일이름: %s\n", __FILE__);
printf("현재 라인번호 : %d\n", __LINE__);
printf("현재 출력되는 함수 : %s\n", __FUNCTION__);
printf("컴파일 날짜 : %s\n", __DATE__);
printf("컴파일 시간 : %s\n", __TIME__);
return 0;
}
실행 :
C:\defexam\defexam\defexam.cpp:main:23: argc=1
파일이름: c:\defexam\defexam\defexam.cpp
현재 라인번호 : 29
현재 출력되는 함수 : main
컴파일 날짜 : Nov 14 2010
컴파일 시간 : 21:55:14
#와 ##
# : 스트링화 한다.
## : 토큰을 연결하여 하나의 토큰으로 만든다.
Token
프로그램을 구성하고 있는 문법적으로 의미 있는 최소 단위
if (i<100) sum+=i;
===> if, (, i, <, 100, ), sum, +=, i, ;
10개의 토큰으로 이루어 진다.
토큰의 예
- 키워드 : int, while, if, else, auto, char, for…
- 식별자 : main, printf, scanf, i, j…
- 연산자 : +, -, *, /, =, <. >=…
- 수치상수 : 124, 12.35, 7E9 등과 같은 수
- 문자상수 : 단일 인용 부호(' ')내의 단일 문자나 문자열
- 특수문자 : (, ), ;와 같이 구분자로 사용되는 문자
- 주해 : /*와 */사이에 있는 임의의 문자열, 컴파일러에 의해 번역되지 않는다.
#예 :
#define QUOTEME(x) #x
printf("%s\n", QUOTEME(1+2));
===>
printf("%s\n", "1+2");
Token concatenation
#define CATTOK(x,y) x##y
int manage;
manage = 10;
printf("%d\n", CATTOK(man,age));
===>
printf("%d\n", manage );
예 1 :
#define FORMAT_(type) FORMAT_##type
#define FORMAT_int "%d"
#define FORMAT_double "%g"
void print_star(const starStruct *const star) {
/* FORMAT_(type) will be replaced with FORMAT_int or FORMAT_double */
#define EXPAND_STAR_MEMBER(member, type) \
printf("%s: " FORMAT_(type) "\n", #member, star->member);
EXPAND_STAR
#undef EXPAND_STAR_MEMBER
}
예 2 :
#define MYCASE(item,id) \
case id: \
item##_##id = id;\
break
switch(x) {
MYCASE(widget,23);
}
===>
case 23:
widget_23 = 23;
break;
예 3 :
#define CONCAT(a, b) a##b
// main 함수
int main(void)
{
int arr〔2〕= { 100, 200 };
printf("%d \n", CONCAT(2, 4));
printf("%d %d \n", CONCAT(arr, 〔0〕), CONCAT(arr, 〔1〕));
return 0;
}
printf 사용시 방법 몇가지
#define print_int(val) printf("%d", val)
#define print_double(val) printf("%g", val
#define DPRINTF(a,args...) fprintf( stderr, "%s:%d:"#a"\n", __FUNCTION__, __LINE__, ##args)
예:
#define DPRINTF(fmt,args,...) printf( "%s:%d:" fmt, __FUNCTION__, __LINE__, ##args)
int main( int argc, char *argv[])
{
int i = 0;
if (argc < 2) {
DPRINTF( "argc=%d", argc);
}
printf("End of program\n");
return 0;
}
#define CHECK1(x,format,args) if(x) {printf(format,args);}
#define fcntl( fd, command, ... ) \
wpurple_fcntl( fd, command, ##__VA_ARGS__ )
#define gprintk(fmt, x... ) printk( "%s: " fmt, __FUNCTION__ , ## x)
다른 예
#define a /*
#<?php echo "\\010Hello, world!\\n"// 2> /dev/null > /dev/null \\
;
// 2> /dev/null; x=a;
$x=5 // 2> /dev/null \\
;
if (($x))
// 2> /dev/null; then
return 0;
// 2> /dev/null; fi
#define e ?>
#define b */
#include
#define main() int main()
#define printf printf(
#define true )
#define function
function main()
{
printf "Hello, world!\\n"true/* 2> /dev/null | grep -v true*/;
return 0;
}
#define c /*
main
#*/
예 :
#define printf(fmt, args...) test_print(fmt, ##args)
int ttyS1_fd;
void test_print(char *fmt, ...)
{
write(ttyS1_fd, fmt, strlen(fmt));
}
int main(void)
{
if ( (ttyS1_fd = open("/dev/ttyS1", O_RDWR|O_NOCTTY)) < 0 ) {
printf(" /dev/ttyS1" open failed\n");
return 1;
}
while (1) {
printf("abcde %d\n", 1);
sleep(1)
}
return 0;
}
#define sum(x,y) (x+y)
#define LEN 100
#define WIDTH 100
char array[LEN][WIDTH];
#undef LEN
#undef WIDTH
printk 사용
참고로 printk 함수는
printk()는 카널의 메시지를 콘솔이나 dmesg, syslog 데몬에게 넘겨주는 일을 한다.
1. printk
include/linux/kernel.h
일반적인 프로그램을 작성할때도 로그정책은 매우 중요하다. 보통 레벨 1은 가장 낮은 수준의 디버그 메시지 레벨 3은 모든 디버그 메시지를 모두 남기는 식으로 정하는데 priorities를 이용해서 발생되는 로그에 레벨을 부여해 줄 수 있다.
priority 는 다음과 같이 커널에 정의되어 있다.
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
2. printk 사용
KERN_INFO의 동일한 표현
printk(KERN_INFO "system ok\n");
printk("<6>" "system ok\n");
printk("<6>system ok\n");
기타 예 :
printk(KERN_INFO "i = %u\n", i);
printk("<0> %s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
레벨에 대한 표시를 하지 않는다면 default 레벨은 "KERN_WARNING" 이다.
3. 커널 메시지 관리 데몬
- klogd : 커널에서 발생하는 메시지를 기록하고 관리한다.
- syslogd : 커널에서 발생한느 메시지와 응용 프로그램에서 요청한 시스템 정보를 기록하고 관리한다.
- /var/log/messages 파일에 모든 커널메시지가 저장된다.
4. 로그 정보보기
- dmesg
- cat /proc/kmsg : 커널 메시지가 발생할 때 즉시 출력.
보통 디버깅 시 정의하는 것을 바꿀 필요가 생긴다. 지금 WindowsCE의 메세지를 PC WIN32 MFC로 바꾸려면 RETAILMSG과 TRACE의 정의가 틀리다. 따라서 이것을 조정하기 위한 정의 이다.
RETAILMSG 함수의 첫번째 인수 n을 제거하는 것이다.
#define RETAILMSG(n, args...) TRACE(##args) ---> ##다음 부터는 그대로
RETAILMSG(1, (TEXT("Invalid parameter to ReadChunk()\r\n")));
===> TRACE( (TEXT("Invalid parameter to ReadChunk()\r\n")));
RETAILMSG(1, (TEXT("Error opening %s. Error code = 0x%08x\n"), pszFilename, GetLastError()));
===> TRACE( (TEXT("Error opening %s. Error code = 0x%08x\n"), pszFilename, GetLastError()));