va_list에 대한 질문입니다.

익명 사용자의 이미지

/*************예제 1 ****************/

int Open(const char *pathname, int oflag, ...)
{
int fd;
va_list ap;
mode_t mode;

if (oflag & O_CREAT) {
va_start(ap, oflag); /* init ap to final named
argument */
mode = va_arg(ap, /*va_*/mode_t);
if ( (fd = open(pathname, oflag, mode)) == -1)
{
printf("open error for %s", pathname);
exit(-1);
}
va_end(ap);
} else {
if ( (fd = open(pathname, oflag)) == -1)
{
printf("open error for %s", pathname);
exit(-1);
}
}
return(fd);
}

/****************예제 2 *********************/

sem_t *
Sem_open(const char *pathname, int oflag, ...)
{
sem_t *sem;
va_list ap;
mode_t mode;
unsigned int value;

if (oflag & O_CREAT) {
va_start(ap, oflag); /* init ap to final named
argument */
mode = va_arg(ap, va_mode_t);
value = va_arg(ap, unsigned int);
if ( (sem = sem_open(pathname, oflag, mode, value)) ==
SEM_FAILED)
err_sys("sem_open error for %s", pathname);
va_end(ap);
} else {
if ( (sem = sem_open(pathname, oflag)) == SEM_FAILED)
err_sys("sem_open error for %s", pathname);
}
return(sem);
}

/***************예제 3**************************/

#include

#define MAXARGS 31

/*
* execl is called by
* execl(file, arg1, arg2, ..., (char *)(0));
*/
int execl (const char *file, const char *args, ...)
{
va_list ap;
char *array[MAXARGS];
int argno = 0;
va_start(ap, args);
while (args != 0) {
array[argno++] = args;
args = va_arg(ap, const char *);
}
va_end(ap);
return execv(file, array);
}

질문 예제 1에서 pathname, oflag를 제외하고 va_arg에서 mode_t라는 타
입으로 딱 하나의 argument만 받습니다.

예제 2에서는 mode_t와 unsigned int라고 하는 type과 함께 argument의 갯
수까지도 알수 있습니다.

결국 예제 1, 예제 2는 변수의 타입과 갯수까지 아는 것인데 왜 굳이 va_
list를 써야만 하는 걸까요?

가령 예제 3의 경우는 NULL까지 계속 char *의 argument를 받는 것이므로
argument의 갯수가 미확정이니까 va_list를 쓸만한 가치가 있는 것 같은
데....예제 1, 예제 2의 경우는 type과 갯수까지 아는 argument를 왜 굳
이 va_list로 받아야 할까요? 정말 궁금합니다.

그리고 만약 갯수와 타입을 모두 알수 없는 가령 printf의 구현을 가정한
다면 이것을 어떻게 구현할 수 있을까요?

va_arg에서 type을 요청하기 때문에 결국 이러한 함수의 구현은 va_list로
도 불가능할 것 같은데요...무슨 다른 방법이 있을까요?

프로그램 고수의 현명한 조언을 기대합니다.

참고로 예제 1, 예제 2는 stevens의 예제입니다.

익명 사용자의 이미지

안녕하세요

상당히 어려운 질문이군요.

일단 macro로 정의된거 먼저 카피해봤습니다.

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof
(int) - 1) )

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF
(t)) )
#define va_end(ap) ( ap = (va_list)0 )

위에서 보시면 알 수 있듯이 va_list를 가지고 address를 하나씩 이동시켜
가면서 값들을 추출하는 것 같군요.
그렇게 된다면 va_list가 시작 위치를 가르켜야 하기 때문에 반드시 필요
하겠져

그리고 시작 위치를 모르는 경우라면 음냐..( printf() )

그건 compiler쪽을 공부해 보시면 쉽게 답이 나올듯합니다.

함수가 호출될때 어떠한 정보들이 push되는지 그리고 그 값들을

어떻게 얻어오는지 등을 알면 va_list없이도 작업이 가능하지 않을까요?

물론 assembly쪽으로도 좀 아셔야겠져.

)

익명 사용자의 이미지

> 결국 예제 1, 예제 2는 변수의 타입과 갯수까지 아는 것인데
> 왜 굳이 va_list를 써야만 하는 걸까요?

써야만 한다는 건 없습니다. 프로그래머가 판단할 일이죠.
그 함수들은 O_CREAT 일때 인자가 3개또는 4개가 되는데,
Stevens 는 이걸 처리할 때는 가변인자가 좋겠다고 판단한
겁니다. 그렇게 판단하지 않는 프로그래머도 있을 수 있구요.

> 그리고 만약 갯수와 타입을 모두 알수 없는 가령 printf의 구현을
> 가정한 다면 이것을 어떻게 구현할 수 있을까요?
> va_arg에서 type을 요청하기 때문에 결국 이러한 함수의 구현은
> va_list로 도 불가능할 것 같은데요...

printf 는 va_list 로 구현합니다. printf 는 첫인자로
포맷 문자열을 갖는데, 결국 그 문자열 안에는 가변 인자로 몇개가
주어졌으며, 그 타입이 무엇인지 나타납니다. % 뒤에 오는 문자에
따라 printf 함수는 switch 하고 va_arg 로 적절한 타입을
얻어 오겠죠. 기타 포맷 문자열에 추가되는 기능들도 물론 구현
해야 될 것이구요...

C 에서는 가변인자 또는 고전적인 프로토타입을 사용할 때
인자를 promotion ( argument promotion rule인가...? 명칭은
잘 생각 안나는군요... )합니다. 예를 들어 float 을 double
로 char 를 int 등으로 promotion 하는 규칙이 있기 때문에
va_arg 를 사용할 때 이들 규칙을 잘 고려해야 됩니다.

익명 사용자의 이미지

두분의 조언으로 많은 도움 받았습니다...

물론, 100% 확실한 건 아니지만 그 나머지는 어차피 저의 몫이 아닌가..
하는 생각이 듭니다.

거듭, 두분의 좋은 답변에 감사드립니다.

그리고 이건 일종의 팁인데...인터넷에서 구한 my_printf source를 올립니
다.

다른 분들께서도 도움을 받기 바랍니다.

#include // for i/o library
#include // for variable argument library

#define my_va_start(VA_LIST,LAST_NAMED_ARG) \
((VA_LIST) = ( (char *)(&(LAST_NAMED_ARG)) + sizeof
(LAST_NAMED_ARG) ))
#define my_va_arg(VA_LIST, SOME_TYPE) \
((VA_LIST) = (char *)(VA_LIST) + sizeof(SOME_TYPE), \
*(SOME_TYPE*)((char *)(VA_LIST) - sizeof(SOME_TYPE)))
#define my_va_end(VA_LIST) ()

void my_printf(char *fmt, ...);
void my_printf_and_va(char *fmt, ...); // same as my_printf(),
// except uses my va_arg
stuff
int main(int argc, char *argv[])
{
const double x = 3.4;
const int q = 4;
char a[] = "hey guy!";
printf("Here's version with standard va_arg\n");
my_printf("%f %d %s\n", x, q, a);
printf("Here's version with my_va_arg\n");
my_printf_and_va("%f %d %s\n", x, q, a);
return 0;
}

void my_printf(char *fmt, ...)
{ // initialize pass over arguments
va_list argl;
va_start(argl, fmt); // beginning after last named argument fmt
for (char *p = fmt; *p; ++p) // format string controls parsing
of args
{
if (*p == '%')
{ switch (*++p)
{ case 'f' double fval=va_arg(argl,double); //
get arg as double
cout << fval; break;
case 'd' int ival=va_arg(argl,int);
cout << ival;
break;
case 's' char *sval = va_arg(argl,char *);
cout << sval; break;
default cout << *p;
break;
}
}
else
cout << *p;
}
va_end(argl);
}

void my_printf_and_va(char *fmt, ...)
{
// initialize pass over arguments
my_va_list argl;
my_va_start(argl, fmt); // beginning after last named argument
fmt
// this loop is identical to that in my_printf() except
// that it uses non-portable version of va_start(),va_arg
(),va_end
for (char *p = fmt; *p; ++p) // format string controls parsing
of args
{
if (*p == '%')
{
switch (*++p)
{
case 'f'
double fval= my_va_arg(argl,double); // get arg
as double
cout << fval; break;
case 'd'
int ival=my_va_arg(argl,int);
cout << ival; break;
case 's' char *sval = my_va_arg(argl,char *);
cout << sval; break;
default
cout << *p;
break;
}
}
else
cout << *p;
}
va_end(argl);
}

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.