본문 바로가기

프로그래밍 언어/C, C++

sprintf, vprintf, svprintf 사용법

목차

int vprintf(const char *_Format,  va_list _ArgList);                          // 가변인자 받는다. printf와 사용법이 같다.

int sprintf(char *_Dest, const char * _Format, ...);                           // 버퍼(_Dest)에 출력 값 담는다.

int vsprintf(char *_Dest, const char *_Format, va_list _ArgList);  // 버퍼(_Dest)에 출력 값 담는다. 가변인자 받는다.

 

 

※ int fprintf(FILE *stream, const char* format, ...);                      // 파일 포인터에 출력 값을 담는다.

vprintf는 printf와 유사하고, vsprintf는 sprintf와 유사하다.

※ <stdio.h> or <cstdio>에 속해 있다.

va_list, va_start, va_arg, va_end는 <stdarg.h>에 속해 있다.


int vprintf(const char *_Format,  va_list _ArgList);

- printf와 유사하지만, 가변인자를 받을 수 있다.

  (cplusplus 문서에 따르면 아래와 같이 나와 있다)

- Print formatted data from variable argument list to stdout(가변 인자를 표준 출력으로 내보낸다)

- Using the elements in the variable argument list identified by arg instead of additional function arguments(함수 상에서 추가적인 인자를 받지 않고, arg로 표현되는 리스트 형태로 받는다)

- arg는 va_starts에 의해 초기화 되어야 한다.

- arg는 사용 후 va_end로 Release 되어야 한다.

void MyVarFunc1(char* pStr, ...)
{
	va_list args;          /* 가변 인자 목록 포인터 */
	va_start(args, pStr);  /* pStr의 경우 "%d + %d = %d\n" 문자열을 가리키며,
                              문자 갯수를 구해서 가변 인자 목록 포인터 설정 */
                              
	vprintf(pStr, args);   /* printf와 유사하게 포맷 정보를 가진 pStr에
                              가변인자 args가 들어간다 */
                              
	va_end(args);          /* 가변 인자 목록을 NULL로 초기화 */
}

int main()
{
	int a = 5, b = 4;
	MyVarFunc1("%d + %d = %d\n", a, b, a + b);
	return 0;
}

>>>

 

va_list: 가변 인자 목록. 가변 인자의 메모리 주소를 저장하는 포인터입니다.

va_start: 가변 인자를 가져올 수 있도록 포인터를 설정합니다.

va_arg: 가변 인자 포인터에서 특정 자료형 크기만큼 값을 가져옵니다.

va_end: 가변 인자 처리가 끝났을 때 포인터를 NULL로 초기화합니다.

(dojang.io/mod/page/view.php?id=577)

 

int sprintf(char* str, const char* format, ...);

 - Write formatted data to string

 - sprintf는 출력 값을 문자열(str)에 저장하는 함수
 - 화면에 출력하는 대신에 화면에 출력할 문자열을 인자로 지정한 문자열(str)에 쓴다.
 - sprintf 함수는 자동적으로 마지막에 NULL('\0')을 붙이기 때문에 버퍼가 출력 문자 보다 항상 커야 한다.
 - (잘 쓰이지는 않음) NULL을 제외한 쓰여진 총 문자 갯수가 반환된다. 

 

#include <stdio.h>
int main() {
  int integer = 123;
  char character = 'c';
  char string[] = "hello, world";
  int* pointer = &integer;
  double pi = 3.141592;
  char buf[100];

  sprintf(buf, "integer : (decimal) %d (octal) %o \n", integer, integer);
  printf("%s \n", buf);

  sprintf(buf, "character : %c \n", character);
  printf("%s \n", buf);

  sprintf(buf, "string : %s \n", string);
  printf("%s \n", buf);

  sprintf(buf, "pointer addr : %p \n", pointer);
  printf("%s \n", buf);

  sprintf(buf, "floating point : %e // %f \n", pi, pi);
  printf("%s \n", buf);

  sprintf(buf, "percent symbol : %% \n");
  printf("%s \n", buf);

  return 0;
}

>>>

 

int vsprintf(char *_Dest, const char * _Format, va_list _Args);

- Write formatted data from variable argument list to string

- sprintf의 버퍼에 출력값을 담는 기능과

- vprintf의 가변인자를 받는 기능을 가지고 있다.

 

void MyVarFunc2(char *pStr, ...)
{
	char szBuf[1024] = { 0, };
	va_list args;
	va_start(args, pStr);

	vsprintf((char *)szBuf, (const char *)pStr, args);

	printf(szBuf);

	va_end(args);
}

int main()
{
	int a = 5, b = 4;
	MyVarFunc2("%d + %d = %d\n", a, b, a + b);
	return 0;
}

>>>

 


예시1(디버깅 용 by Serial)

void DPRINT(DebuggingLevel Level, const sint8 * pStr, ...)
{
    if(DebuggingLevel < eLevel)
    {
        return;
    }

    sint8 cMsg[BUFFER_SIZE + 1] ={0,};

    va_list args;
    va_start(args, pStr);
    vsprintf((char *)cMsg, (const char *)pStr, args);
    va_end(args);

    Print_Serial(cMsg); // Serial 프린트 앞 뒤로, SpinLock or Mutex Lock/Unlock 붙여준다.
}

 

예시2(디버깅 용 by File)

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#define LOG_FILE		"Log.txt"
#define DEBUG_FILE		(int8*)__FILE__, (int8*)__FUNCTION__, (uint32)__LINE__

void PrintLog(uint32 ulLevel, int8* pFile, int8* pFunc, uint32 ulLine, int8 *fmt, ...) // [Option1]
//void PrintLog( char const * const format, ... ) // [Option2]
{
   FILE *fp;
   
   va_list args;
   int len;
   char * buffer;

   va_start( args, format );
   len = _vscprintf( format, args + 1); // _vscprintf does not count 
                                        // +1 means terminating '\0'
   buffer = (char *) malloc( len * sizeof(char) );
   if ( NULL != buffer )
   {
      vsprintf_s( buffer, len, format, args );
      //puts( buffer );
      // or
      if(fopen_s(&fp, LOG_FILE, "a+") == 0)
      {
          fprintf(fp, "%s(%d): %s\t %s", pFile, uLine, pFunc, buffer); // [Option1]
          //fprintf(fp, "%s", buffer); // [Option2]
          fclose();
      }
      free( buffer );
   }
   va_end( args );
}

int main()
{
	PrintLog(DBGLvl, DEBUG_FILE, "Error happens \n");
}

 


※ 텍스트 파일 vs 이진 파일

- 텍스트 파일은 사람이 읽을 수 있는 텍스트가 들어 있는 파일이며 아스키 코드를 이용하여 표현된다.  

- 메모장에 예를 들어 '35'가 쓰여있으면 이건 아스키 값이다.

- 텍스트 파일은 OS 마다 동일하게 저장된다. 따라서, 이식성이 뛰어나다. 하지만, 읽어 들일 때 아스키를 해석하는 함수(e.g. fscanf) 가 필요하여 해석하는 속도가 이진 파일에 비해 떨어진다.

 

  입력 함수 출력 함수
문자 단위 int fgetc(FILE *fp) int fputc(int c, FILE *fp)
문자열 단위 char *fgets(char *buf, int n, FILE *fp) char *fputs(char *buf, FILE *fp)
서식화된 입출력 fscanf(FILE *fp, ...) fprintf(FILE *fp, ...)
이진 데이터 size_t fread(char *buffer, int size, int count, FILE *fp) size_t fwrite(char *buffer, int size, int count, FILE *fp)

fgets는 버퍼 크기(n) 만큼 읽되, 널문자(\0)를 포함하여 읽는다(따라서 전체 문자열 갯수는 n-1 이다)

fgets는 개행문자(\n)가 있으면 개행문자 까지 읽고, 읽는 것을 멈춘다.

※ 개인적으로 '서식화된 입/출력'과 '이진 데이터 입/출력' 즉, 아래 2개 함수 용법만 알고 있으면 될것 같다. 

 

※ puts 용법

int puts(const char* str);

str 이 가리키는 C 문자열을 표준 출력(stdout) 에 쓴 뒤 (이때 '\0' 앞에 까지 복사하여 쓴다. NULL 문자는 표준 출력에 복사하지 않는다) 그리고, 자동으로 개행 문자('\n') 도 추가로 쓴다.
(즉 문자열에 \n 이 마지막에 없더라도 한 줄 개행이 되어 출력된다)

※ fflush 용법

int fflush( FILE *stream );

- 버퍼의 데이터를 꺼내어 스트림에 쏟아 붇는 함수이다.

- 참고로, window에서는 stdout, stderr가 동일 버퍼이며, 데이터가 들어오면 바로 비우지만,

- 리눅스는 stdout, stderr가 다른 버퍼이며, stderr는 바로 비우며 stdout은 개행 문자가 나타나면 비운다. 

- stdout, stderr로 파일 포인터인가 보다

 

※ stream에 입력 스트림이 들어갈 경우 OS 마다 동작이 달라 주의해야 한다. e.g. fflush(stdin)

리눅스의 경우 fflush(stdin)을 하면 개행 문자('\n')가 버퍼에 남게 된다. 

따라서, 버퍼를 완전히 비우는 __furge(FILE *stream)을 권장한다.

혹은 '\n' 을 입력 안받기 위해 while(getchar() != '\n')을 사용하도록 한다.


[Reference]

modoocode.com/66

psychoria.tistory.com/38

www.cplusplus.com/reference/cstdio/

docs.microsoft.com/ko-kr/cpp/c-runtime-library/reference/vsprintf-s-vsprintf-s-l-vswprintf-s-vswprintf-s-l?view=msvc-160

www.basic4mcu.com/bbs/board.php?bo_table=gac&wr_id=2824

andyader.blogspot.com/2013/09/fflush.html

반응형