How to count the no of arguments passed to the function in following program:
如何在以下程序中计算传递给函数的参数no:
#include<stdio.h>
#include<stdarg.h>
void varfun(int i, ...);
int main(){
varfun(1, 2, 3, 4, 5, 6);
return 0;
}
void varfun(int n_args, ...){
va_list ap;
int i, t;
va_start(ap, n_args);
for(i=0;t = va_arg(ap, int);i++){
printf("%d", t);
}
va_end(ap);
}
This program's output over my gcc compiler under ubuntu 10.04:
这个程序在ubuntu 10.04下的gcc编译器上的输出:
234561345138032514932134513792
so how to find how many no. of arguments actually passed to the function?
如何求出有多少。实际上传递给函数的参数?
9 个解决方案
#1
36
You can't. You have to manage for the caller to indicate the number of arguments somehow. You can:
你不能。您必须设法让调用者以某种方式指示参数的数量。您可以:
- Pass the number of arguments as the first variable
- 将参数数量作为第一个变量传递。
- Require the last variable argument to be null, zero or whatever
- 要求最后一个变量参数为null, 0或其他
- Have the first argument describe what is expected (eg. the printf format string dictates what arguments should follow)
- 让第一个论点描述预期的东西。printf格式字符串指定了应该遵循的参数)
#2
7
You can let the preprocessor help you cheat using this strategy, stolen and tweaked from another answer:
你可以让预处理器帮助你使用这个策略作弊,从另一个答案中窃取和调整:
#include <stdio.h>
#include <stdarg.h>
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \
_71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \
_91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \
_101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \
_111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \
_121,_122,_123,_124,_125,_126,_127,N,...) N
#define PP_RSEQ_N() \
127,126,125,124,123,122,121,120, \
119,118,117,116,115,114,113,112,111,110, \
109,108,107,106,105,104,103,102,101,100, \
99,98,97,96,95,94,93,92,91,90, \
89,88,87,86,85,84,83,82,81,80, \
79,78,77,76,75,74,73,72,71,70, \
69,68,67,66,65,64,63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
void _variad(size_t argc, ...);
#define variad(...) _variad(PP_NARG(__VA_ARGS__), __VA_ARGS__)
void _variad(size_t argc, ...) {
va_list ap;
va_start(ap, argc);
for (int i = 0; i < argc; i++) {
printf("%d ", va_arg(ap, int));
}
printf("\n");
va_end(ap);
}
int main(int argc, char* argv[]) {
variad(2, 4, 6, 8, 10);
return 0;
}
There's a few clever tricks here.
这里有一些技巧。
1) Instead of calling the variadic function directly, you're calling a macro that counts the arguments and passes the argument count as the first argument to the function. The end result of the preprocessor on main looks like:
不要直接调用变量函数,而是调用宏来计数参数,并将参数计数作为函数的第一个参数。主处理器的最终结果是:
_variad(5, 2, 4, 6, 8, 10);
2) PP_NARG
is a clever macro to count arguments.
2) PP_NARG是一个计算参数的聪明宏。
The workhorse here is PP_ARG_N
. It returns its 128th argument, by ignoring the first 127 arguments (named arbitrarily _1
_2
_3
etc.), naming the 128th argument N
, and defining the result of the macro to be N
.
这里的workhorse是PP_ARG_N。它返回第128个参数,忽略前127个参数(任意命名为_1 _2 _3等),命名第128个参数N,并定义宏的结果为N。
PP_NARG
invokes PP_ARG_N
with __VA_ARGS__
concatenated with PP_RSEQ_N
, a reversed sequence of numbers counting from 127 down to 0.
PP_NARG调用PP_ARG_N,用__VA_ARGS__与PP_RSEQ_N连接,这是一个从127到0计数的反向序列。
If you provide no arguments, the 128th value of PP_RSEQ_N
is 0. If you pass one argument to PP_NARG
, then that argument will be passed to PP_ARG_N
as _1
; _2
will be 127, and the 128th argument to PP_ARG_N
will be 1. Thus, each argument in __VA_ARGS__
bumps PP_RSEQ_N
over by one, leaving the correct answer in the 128th slot.
如果不提供参数,则PP_RSEQ_N的128个值为0。如果您将一个参数传递给PP_NARG,那么该参数将作为_1传递给PP_ARG_N;_2将是127,第128个参数PP_ARG_N将是1。因此,__VA_ARGS__中的每一个参数都在第128个槽中留下正确的答案,从而使PP_RSEQ_N除以1。
(Apparently 127 arguments is the maximum C allows.)
(显然,127个参数是C允许的最大参数。)
#3
6
You can't. Something else has to tell you (for instance for printf, it's implied by the number of % format descriptors in the format string)
你不能。必须告诉您一些其他的东西(例如printf,它是由格式字符串中的% format描述符的数量所暗示的)
#4
4
If you have a C99 compliant compiler (including the preprocessor) you can circumvent this problem by declaring a macro that computes the number of arguments for you. Doing this yourself is a bit tricky, you may use P99_VA_ARGS
from the P99 macro package to achieve this.
如果您有一个兼容C99的编译器(包括预处理器),您可以通过声明一个为您计算参数数量的宏来避免这个问题。自己做这个有点棘手,您可以使用来自P99宏包的P99_VA_ARGS来实现这一点。
#5
3
You can't. varargs aren't designed to make this possible. You need to implement some other mechanism to tell the function how many arguments there are. One common choice is to pass a sentinel argument at the end of the parameter list, e.g.:
你不能。varargs并不是为了实现这一点而设计的。您需要实现一些其他机制来告诉函数有多少参数。一个常见的选择是在参数列表的末尾传递一个sentinel参数,例如:
varfun(1, 2, 3, 4, 5, 6, -1);
Another is to pass the count at the beginning:
另一种方法是在开始时通过计数:
varfun(6, 1, 2, 3, 4, 5, 6);
This is cleaner, but not as safe, since it's easier to get the count wrong, or forget to update it, than it is to remember and maintain the sentinel at the end.
这是干净的,但不是那么安全,因为它更容易弄错计数,或忘记更新它,而不是记住和维护最后的哨兵。
It's up to you how you do it (consider printf's model, in which the format string determines how many — and what type — of arguments there are).
这取决于您如何执行它(考虑printf的模型,其中格式字符串决定了有多少种类型的参数)。
#6
3
The safest way is as described above. But if you REALLY need to know the number of arguments without adding the extra argument mentioned then you can do it this way (but note that it is very machine dependent, OS dependent and even, in rare cases, compiler dependent). I ran this code using Visual Studio 2013 on a 64 bit DELL E6440.
最安全的方法如上所述。但是,如果您确实需要知道参数的数量,而不添加所提到的额外参数,那么您可以这样做(但是请注意,这是非常依赖于机器的、依赖于操作系统的,甚至在极少数情况下,依赖于编译器的)。我在64位的DELL E6440上使用Visual Studio 2013运行了这段代码。
Another point, at the point where I divided by sizeof(int), that was because all of my arguments were int's. If you have different size arguments, there my need to be some adjustment there.
另一点,在我除以sizeof(int)的时候,因为我所有的参数都是int的。如果你有不同的尺寸参数,我需要做一些调整。
This relies on the calling program to use the standard C calling convention. (varfun() gets the number of arguments from the "add esp,xxx" and there are two forms of the add, (1) short form and (2) long form. In the 2nd test I passed a struct because I wanted to simulate lots of arguments to force the long form).
这依赖于调用程序来使用标准的C调用约定。(varfun()从“add esp,xxx”中获取参数的数量,并且有两种形式的add, (1) short form和(2)long form。在第2个测试中,我通过了一个struct,因为我想要模拟大量的参数来强制执行长表单)。
The answers printed will be 6 and 501.
打印的答案将是6和501。
varfun(1, 2, 3, 4, 5, 6);
00A03CC8 6A 06 push 6
00A03CCA 6A 05 push 5
00A03CCC 6A 04 push 4
00A03CCE 6A 03 push 3
00A03CD0 6A 02 push 2
00A03CD2 6A 01 push 1
00A03CD4 E8 E5 D3 FF FF call _varfun (0A010BEh)
00A03CD9 83 C4 18 add esp,18h
varfun(1, x);
00A03CDC 81 EC D0 07 00 00 sub esp,7D0h
00A03CE2 B9 F4 01 00 00 mov ecx,1F4h
00A03CE7 8D B5 28 F8 FF FF lea esi,[x]
00A03CED 8B FC mov edi,esp
00A03CEF F3 A5 rep movs dword ptr es:[edi],dword ptr [esi]
00A03CF1 6A 01 push 1
00A03CF3 E8 C6 D3 FF FF call _varfun (0A010BEh)
00A03CF8 81 C4 D4 07 00 00 add esp,7D4h
#include<stdio.h>
#include<stdarg.h>
void varfun(int i, ...);
int main()
{
struct eddy
{
int x[500];
} x = { 0 };
varfun(1, 2, 3, 4, 5, 6);
varfun(1, x);
return 0;
}
void varfun(int n_args, ...)
{
va_list ap;
unsigned long *p;
unsigned char *p1;
unsigned int nargs;
va_start(ap, n_args);
p = (long *)(ap - _INTSIZEOF(int) - _INTSIZEOF(&varfun));
p1 = (char *)*p;
if (*p1 == 0x83) // short add sp,x
{
nargs = p1[2] / sizeof(int);
}
else
{
nargs = *(unsigned long *)(p1+2) / sizeof(int);
}
printf("%d\n", nargs);
va_end(ap);
}
#7
0
You could also use a meaningful value that indicates end of arguments. Like a 0 or -1. Or a max type size like 0xFFFF for a ushort
.
您还可以使用一个有意义的值来表示参数的结束。比如0或-1。或者最大类型大小,比如ushort的0xFFFF。
Otherwise, you need to mention the count upfront or make it deductible from another argument (format
for printf()
like functions).
否则,您需要预先提到计数,或者将它从另一个参数(printf()之类的函数的格式)中扣除。
#8
0
In this code it is possible when you pass only pointer
在这段代码中,只传递指针是可能的
# include <unistd.h>
# include <stdarg.h>
# include <string.h>
# include <errno.h>
size_t __print__(char * str1, ...);
# define print(...) __print__(NULL, __VA_ARGS__, NULL)
# define ENDL "\n"
int main() {
print("1", ENDL, "2", ENDL, "3", ENDL);
return 0;
}
size_t __print__(char * str1, ...) {
va_list args;
va_start(args, str1);
size_t out_char = 0;
char * tmp_str;
while((tmp_str = va_arg(args, char *)) != NULL)
out_char = out_char + write(1, tmp_str,strlen(tmp_str));
va_end(args);
return out_char;
}
#9
-2
Its possible and it is simple, just add another variable k in the loop and assign it initially 1, try this code
它可能而且很简单,只需在循环中添加另一个变量k,并将其赋值为1,尝试这段代码。
#include <stdio.h>
#include <stdarg.h>
void varfun(int i, ...);
int main(){
varfun(1,2);
return 0;
}
void varfun(int n_args, ...)
{
va_list ap;
int i, t, k;
k = 1;
va_start(ap, n_args);
for(i=0;i <= va_arg(ap, int);i++){
k+=1;
}
printf("%d",k);
va_end(ap);
}
#1
36
You can't. You have to manage for the caller to indicate the number of arguments somehow. You can:
你不能。您必须设法让调用者以某种方式指示参数的数量。您可以:
- Pass the number of arguments as the first variable
- 将参数数量作为第一个变量传递。
- Require the last variable argument to be null, zero or whatever
- 要求最后一个变量参数为null, 0或其他
- Have the first argument describe what is expected (eg. the printf format string dictates what arguments should follow)
- 让第一个论点描述预期的东西。printf格式字符串指定了应该遵循的参数)
#2
7
You can let the preprocessor help you cheat using this strategy, stolen and tweaked from another answer:
你可以让预处理器帮助你使用这个策略作弊,从另一个答案中窃取和调整:
#include <stdio.h>
#include <stdarg.h>
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \
_71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \
_91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \
_101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \
_111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \
_121,_122,_123,_124,_125,_126,_127,N,...) N
#define PP_RSEQ_N() \
127,126,125,124,123,122,121,120, \
119,118,117,116,115,114,113,112,111,110, \
109,108,107,106,105,104,103,102,101,100, \
99,98,97,96,95,94,93,92,91,90, \
89,88,87,86,85,84,83,82,81,80, \
79,78,77,76,75,74,73,72,71,70, \
69,68,67,66,65,64,63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
void _variad(size_t argc, ...);
#define variad(...) _variad(PP_NARG(__VA_ARGS__), __VA_ARGS__)
void _variad(size_t argc, ...) {
va_list ap;
va_start(ap, argc);
for (int i = 0; i < argc; i++) {
printf("%d ", va_arg(ap, int));
}
printf("\n");
va_end(ap);
}
int main(int argc, char* argv[]) {
variad(2, 4, 6, 8, 10);
return 0;
}
There's a few clever tricks here.
这里有一些技巧。
1) Instead of calling the variadic function directly, you're calling a macro that counts the arguments and passes the argument count as the first argument to the function. The end result of the preprocessor on main looks like:
不要直接调用变量函数,而是调用宏来计数参数,并将参数计数作为函数的第一个参数。主处理器的最终结果是:
_variad(5, 2, 4, 6, 8, 10);
2) PP_NARG
is a clever macro to count arguments.
2) PP_NARG是一个计算参数的聪明宏。
The workhorse here is PP_ARG_N
. It returns its 128th argument, by ignoring the first 127 arguments (named arbitrarily _1
_2
_3
etc.), naming the 128th argument N
, and defining the result of the macro to be N
.
这里的workhorse是PP_ARG_N。它返回第128个参数,忽略前127个参数(任意命名为_1 _2 _3等),命名第128个参数N,并定义宏的结果为N。
PP_NARG
invokes PP_ARG_N
with __VA_ARGS__
concatenated with PP_RSEQ_N
, a reversed sequence of numbers counting from 127 down to 0.
PP_NARG调用PP_ARG_N,用__VA_ARGS__与PP_RSEQ_N连接,这是一个从127到0计数的反向序列。
If you provide no arguments, the 128th value of PP_RSEQ_N
is 0. If you pass one argument to PP_NARG
, then that argument will be passed to PP_ARG_N
as _1
; _2
will be 127, and the 128th argument to PP_ARG_N
will be 1. Thus, each argument in __VA_ARGS__
bumps PP_RSEQ_N
over by one, leaving the correct answer in the 128th slot.
如果不提供参数,则PP_RSEQ_N的128个值为0。如果您将一个参数传递给PP_NARG,那么该参数将作为_1传递给PP_ARG_N;_2将是127,第128个参数PP_ARG_N将是1。因此,__VA_ARGS__中的每一个参数都在第128个槽中留下正确的答案,从而使PP_RSEQ_N除以1。
(Apparently 127 arguments is the maximum C allows.)
(显然,127个参数是C允许的最大参数。)
#3
6
You can't. Something else has to tell you (for instance for printf, it's implied by the number of % format descriptors in the format string)
你不能。必须告诉您一些其他的东西(例如printf,它是由格式字符串中的% format描述符的数量所暗示的)
#4
4
If you have a C99 compliant compiler (including the preprocessor) you can circumvent this problem by declaring a macro that computes the number of arguments for you. Doing this yourself is a bit tricky, you may use P99_VA_ARGS
from the P99 macro package to achieve this.
如果您有一个兼容C99的编译器(包括预处理器),您可以通过声明一个为您计算参数数量的宏来避免这个问题。自己做这个有点棘手,您可以使用来自P99宏包的P99_VA_ARGS来实现这一点。
#5
3
You can't. varargs aren't designed to make this possible. You need to implement some other mechanism to tell the function how many arguments there are. One common choice is to pass a sentinel argument at the end of the parameter list, e.g.:
你不能。varargs并不是为了实现这一点而设计的。您需要实现一些其他机制来告诉函数有多少参数。一个常见的选择是在参数列表的末尾传递一个sentinel参数,例如:
varfun(1, 2, 3, 4, 5, 6, -1);
Another is to pass the count at the beginning:
另一种方法是在开始时通过计数:
varfun(6, 1, 2, 3, 4, 5, 6);
This is cleaner, but not as safe, since it's easier to get the count wrong, or forget to update it, than it is to remember and maintain the sentinel at the end.
这是干净的,但不是那么安全,因为它更容易弄错计数,或忘记更新它,而不是记住和维护最后的哨兵。
It's up to you how you do it (consider printf's model, in which the format string determines how many — and what type — of arguments there are).
这取决于您如何执行它(考虑printf的模型,其中格式字符串决定了有多少种类型的参数)。
#6
3
The safest way is as described above. But if you REALLY need to know the number of arguments without adding the extra argument mentioned then you can do it this way (but note that it is very machine dependent, OS dependent and even, in rare cases, compiler dependent). I ran this code using Visual Studio 2013 on a 64 bit DELL E6440.
最安全的方法如上所述。但是,如果您确实需要知道参数的数量,而不添加所提到的额外参数,那么您可以这样做(但是请注意,这是非常依赖于机器的、依赖于操作系统的,甚至在极少数情况下,依赖于编译器的)。我在64位的DELL E6440上使用Visual Studio 2013运行了这段代码。
Another point, at the point where I divided by sizeof(int), that was because all of my arguments were int's. If you have different size arguments, there my need to be some adjustment there.
另一点,在我除以sizeof(int)的时候,因为我所有的参数都是int的。如果你有不同的尺寸参数,我需要做一些调整。
This relies on the calling program to use the standard C calling convention. (varfun() gets the number of arguments from the "add esp,xxx" and there are two forms of the add, (1) short form and (2) long form. In the 2nd test I passed a struct because I wanted to simulate lots of arguments to force the long form).
这依赖于调用程序来使用标准的C调用约定。(varfun()从“add esp,xxx”中获取参数的数量,并且有两种形式的add, (1) short form和(2)long form。在第2个测试中,我通过了一个struct,因为我想要模拟大量的参数来强制执行长表单)。
The answers printed will be 6 and 501.
打印的答案将是6和501。
varfun(1, 2, 3, 4, 5, 6);
00A03CC8 6A 06 push 6
00A03CCA 6A 05 push 5
00A03CCC 6A 04 push 4
00A03CCE 6A 03 push 3
00A03CD0 6A 02 push 2
00A03CD2 6A 01 push 1
00A03CD4 E8 E5 D3 FF FF call _varfun (0A010BEh)
00A03CD9 83 C4 18 add esp,18h
varfun(1, x);
00A03CDC 81 EC D0 07 00 00 sub esp,7D0h
00A03CE2 B9 F4 01 00 00 mov ecx,1F4h
00A03CE7 8D B5 28 F8 FF FF lea esi,[x]
00A03CED 8B FC mov edi,esp
00A03CEF F3 A5 rep movs dword ptr es:[edi],dword ptr [esi]
00A03CF1 6A 01 push 1
00A03CF3 E8 C6 D3 FF FF call _varfun (0A010BEh)
00A03CF8 81 C4 D4 07 00 00 add esp,7D4h
#include<stdio.h>
#include<stdarg.h>
void varfun(int i, ...);
int main()
{
struct eddy
{
int x[500];
} x = { 0 };
varfun(1, 2, 3, 4, 5, 6);
varfun(1, x);
return 0;
}
void varfun(int n_args, ...)
{
va_list ap;
unsigned long *p;
unsigned char *p1;
unsigned int nargs;
va_start(ap, n_args);
p = (long *)(ap - _INTSIZEOF(int) - _INTSIZEOF(&varfun));
p1 = (char *)*p;
if (*p1 == 0x83) // short add sp,x
{
nargs = p1[2] / sizeof(int);
}
else
{
nargs = *(unsigned long *)(p1+2) / sizeof(int);
}
printf("%d\n", nargs);
va_end(ap);
}
#7
0
You could also use a meaningful value that indicates end of arguments. Like a 0 or -1. Or a max type size like 0xFFFF for a ushort
.
您还可以使用一个有意义的值来表示参数的结束。比如0或-1。或者最大类型大小,比如ushort的0xFFFF。
Otherwise, you need to mention the count upfront or make it deductible from another argument (format
for printf()
like functions).
否则,您需要预先提到计数,或者将它从另一个参数(printf()之类的函数的格式)中扣除。
#8
0
In this code it is possible when you pass only pointer
在这段代码中,只传递指针是可能的
# include <unistd.h>
# include <stdarg.h>
# include <string.h>
# include <errno.h>
size_t __print__(char * str1, ...);
# define print(...) __print__(NULL, __VA_ARGS__, NULL)
# define ENDL "\n"
int main() {
print("1", ENDL, "2", ENDL, "3", ENDL);
return 0;
}
size_t __print__(char * str1, ...) {
va_list args;
va_start(args, str1);
size_t out_char = 0;
char * tmp_str;
while((tmp_str = va_arg(args, char *)) != NULL)
out_char = out_char + write(1, tmp_str,strlen(tmp_str));
va_end(args);
return out_char;
}
#9
-2
Its possible and it is simple, just add another variable k in the loop and assign it initially 1, try this code
它可能而且很简单,只需在循环中添加另一个变量k,并将其赋值为1,尝试这段代码。
#include <stdio.h>
#include <stdarg.h>
void varfun(int i, ...);
int main(){
varfun(1,2);
return 0;
}
void varfun(int n_args, ...)
{
va_list ap;
int i, t, k;
k = 1;
va_start(ap, n_args);
for(i=0;i <= va_arg(ap, int);i++){
k+=1;
}
printf("%d",k);
va_end(ap);
}