C 함수의 호출 원리를 이용한 sprintf() 의 약식 구현

onezero3의 이미지

C 함수의 호출 원리를 이용한 sprintf() 의 약식 구현 입니다. va_start() 나 va_end() 함수를 사용하여 구현할 수도 있지만, 이것도 stack의 동작을 숨기고 있어서 좀더 low level 로 구현해 보았습니다.
date 함수와 같이 자신만의 형식으로 포맷을 재구성할 때 사용할 수 있습니다.

/*+-------------------------------------------------------------------------+
  |  FILE: sprintf.c                                                        |
  |  Version: 0.1                                                           |
  |                                                                         |
  |  Copyright (c) 2003 Chun Joon Sung                                      |
  |  Email: chunjoonsung@hanmail.net                                        |
  +-------------------------------------------------------------------------+*/
char *itoa( char *a, int i)
{
	int sign=0;
	int temp=0;
	char buf[16];
	char *ptr;

	ptr = buf;

	/* zero then return */
	if( i )
	{
		/* make string in reverse form */
		if( i < 0 )
			{ i = ~i + 1; sign++; }
		while( i )
			{ *ptr++ = (i % 10) + '0'; i = i / 10; }
		if( sign )
			*ptr++ = '-';
		*ptr = '\0';

		/* copy reverse order */
		for( i=0; i < strlen(buf); i++ )
			*a++ = buf[strlen(buf)-i-1];
	}	
	else
		*a++ = '0';

	return a;
}

char *xtoa( char *a, unsigned int x, int opt)
{
	int i;
	int sign=0;
	int temp=0;
	char buf[16];
	char *ptr;

	ptr = buf;

	/* zero then return */
	if( x )
	{
		/* make string in reverse form */
		while( x )
			{ *ptr++ = (x&0x0f)<10 ? (x&0x0f)+'0' : (x&0x0f)-10+opt; x>>= 4; }

		*ptr = '\0';

		/* copy reverse order */
		for( i=0; i < strlen(buf); i++ )
			*a++ = buf[strlen(buf)-i-1];
	}
	else	
		*a++ = '0';

	return a;
}

long _sprintf(buf, format, arg)
char *buf;
char *format;
long  arg;
{
	int cont_flag;
	int value;
	int quit;
	char *start=buf;
	long *argp=(long *)&arg;
	char *p;

    while( *format )
	{
		if( *format != '%' )	/* 일반적인 문자 */
		{
			*buf++ = *format++;
			continue;
		}

		format++;				/* skip '%' */

		if( *format == '%' )	/* '%' 문자가 연속 두번 있는 경우 */
		{
			*buf++ = *format++;
			continue;
		}
		
		switch( *format )
		{
			case 'c' :
				*buf++ = *(char *)argp++;
				break;

			case 'd' :
				buf = itoa(buf,*(int *)argp++);
				break;

			case 'x' : 
				buf = xtoa(buf,*(unsigned int *)argp++,'a');
				break;

			case 'X' : 
				buf = xtoa(buf,*(unsigned int *)argp++,'A');
				break;

			case 's' :
				p=*(char **)argp++;
				while(*p) 
						*buf++ = *p++;
				break;

			default :
				*buf++ = *format; /* % 뒤에 엉뚱한 문자인 경우 */
				break;
        }

		format++;
    }
    *buf = '\0';

    return(buf-start);
}

main()
{
	char buf[80];

	_sprintf( buf, "%d, %x, %X, %s\n", 1234, 0xabcd, 0xabcd, "abcd"); 
	puts(buf);
}
Forums: 
pynoos의 이미지

stdarg 계열 함수가 지원하는 것이 architecture 마다 다른 것을 감싸기 위해 있는 것이고, i386 계열에서는 이렇게 동작하는 것이 맞겠지요.

모든 arch에서 argument가 stack 으로만 전달되는 것은 아니니까 사용에 제약은 있겠습니다.

또한가지.. 이것은 C에서만 동작하겠습니다. argument 를 통해 name mangling이 일어나는 C++에서는 호출하는 쪽에서볼때, 다른 함수를 호출하게 되고, 결과적으로 link가 안됩니다. C 에서도 만약 argument가 다른 것을 확인한다면, compile 부터 안될 것입니다.

만약, 위 소스가 컴파일/링크가 제대로 되는 환경이라면, 여전히 위 소스는 stack에 전달되는 것을 이해하기에는 좋은 예제입니다.

onezero3의 이미지

이 함수는 원래 embedded target 에서 커다란 라이브러리를 올릴 수 없어서 꼭필요한 함수인 sprintf() 만 구현 하였던 것 입니다.
제가 사용해본 대부분의 32비트 프로세서에서는 잘 동작 합니다.
C 함수의 Calling Convension을 잘 따르는 컴파일러라면, 그리고 어셈블리로 된 Source 와 함께 링크가능한 컴파일러라면 문제 없이 동작 합니다.

ihavnoid의 이미지

혹시 모르는 분들이 계실까 해서....

newlib에 보면 siprintf라는 게 있습니다...
http://sources.redhat.com/newlib/

예전에 프로젝트 할 때 잘 써먹었었죠... :)

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

antibug의 이미지

예전에 8051가지고 작업하는데...
(물론 8051에는 va_list도 있고, sprintf도, vsprintf도 있습니다만)
프로그램 메모리(롬이 모자랐는지 램이 모자랐는지는 잘 모르겠군요.)가
모자라는 상황에... -.-;

이리저리 고민하다가 이유없이 플로팅 포인트 라이브러리가 포함되어 있는걸
보고 printf 계열 함수를 몽땅 제거했습니다. 물론 printf 계열 함수를 다
새로 만들어줘야 했죠. 속도에는 문제가 좀 있었지만 그럭저럭 제한된 공간안에
적당히 구겨넣을 수는 있었습니다.

좋은 환경에서는 저런짓 할 필요가 거의 없다고 보여지네요. ^^;

--------------------------------------
재미없는 일은 하지 말자는 인간 쓰레기.
-.-;

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.