Era*_*NLI 9 c arguments function
In a C function, I want to check if an input argument ('value' in my case) is presented or not.
i.e.:
void Console(char string[], int32_t value)
{
// write string here
// write value here, if it exists
}
Run Code Online (Sandbox Code Playgroud)
When used if(value != NULL) statement, my Console() function sends 4096
How can I check and act based on argument existence?
Bas*_*tch 11
C中通常不允许使用可选参数(但它们存在于C++和Ocaml等中......).唯一的例外是可变函数(如printf).
顺便说一下,你可以定义一些宏来填充"缺失"参数,所以如果你有
void console(const char*, int32_t);
Run Code Online (Sandbox Code Playgroud)
你也可以
#define console_plain(Msg) console((Msg),0)
Run Code Online (Sandbox Code Playgroud)
而这可能是某些标题中的一些内联函数,例如
static void inline console_plain (const char*msg)
{ console(msg, 0); }
Run Code Online (Sandbox Code Playgroud)
然后open在别处使用
然后你的可变参数函数应该定义允许的参数和参数(在非空的固定参数序列之后).并使用stdarg(3)来获取这些可变参数(实际).
实际参数主要在编译时知道,而不是在运行时.因此,您需要一个约定,该约定通常定义从所需的固定参数中允许哪个可变参数.特别是,您无法测试是否存在参数(该信息在运行时丢失).
顺便说一句,使用可变参数函数,您通常会失去大多数C编译器提供的类型检查(至少在您启用所有警告时,例如<stdarg.h>).如果使用GCC
你可能有一些功能console_plain("hello here")-S(如gcc -Wall -Wextra,__attribute__在原型,....),以帮助这一点.您甚至可以format使用MELT自定义添加自己的属性进行自己的类型检查.
如果要区分带有一个或两个参数的函数调用,可以使用宏。
虽然您可以重现您想要的行为,但有一些事项需要注意:
宏实现隐藏了代码的重载,他们看不到Console宏。C 非常注重查看细节,因此如果您有两个不同的函数,它们可能应该有不同的名称,也许cons_str和cons_str_int。
如果您传递两个以上的参数,或者这些参数与所需的 C string 和 int 类型不兼容,则宏将生成编译器错误。这实际上是一件好事。
像printf使用 from 接口的真正的可变参数函数<stdarg.h>必须能够派生可变参数的类型和数量。在 中printf,这是通过%格式说明符完成的。宏可以根据参数的数量在不同的实现之间切换。
无论如何,这是一个实现。谨慎行事。
#include <stdlib.h>
#include <stdio.h>
#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define NARGS_(_5, _4, _3, _2, _1, N, ...) N
#define CONC(A, B) CONC_(A, B)
#define CONC_(A, B) A##B
#define Console(...) CONC(Console, NARGS(__VA_ARGS__))(__VA_ARGS__)
void Console1(const char string[])
{
printf("%s\n", string);
}
void Console2(const char string[], int32_t value)
{
printf("%s: %d\n", string, value);
}
int main()
{
Console("Hello");
Console("Today's number is", 712);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
听起来好像您正在尝试使用黑客技术来潜在地便利您自己或“以写模式”打开源代码的任何人。我之所以说“处于写模式”(不是读/写),是因为所有隐藏的代码以及您需要的神奇宏,使得此类代码很难阅读。C不是聪明的语言。编译器可能很聪明,但是语言语义相当繁琐。您应严格遵守规则,否则可能会冒出劣质或劣质软件的风险-根本无法工作。
“正确”的方式做到这一点,而无需创建一个全新的编程语言是提供两个参数,而当第二不宜使用,要么原样传递NULL,如果它是一个指针或一些不包括数量,例如-1,如果它是数字类型。
另一种方法是使用提示名称创建两个单独的函数,例如:
console和console_full。分别带有一个和两个参数。
但是,如果您仍然不满意上述方法,则可以包括stdarg.h为您做的。
void Console (char *string, ...) /* Note the ... */
{
va_list param;
int32_t optValue = (-1); /* -1 would indicate optValue is to be ignored */
// write string here
va_start(param, string);
optValue = va_arg(param, int32_t);
if(optValue != (-1))
{
/* Work with `optValue` */
}
va_end(param);
}
Run Code Online (Sandbox Code Playgroud)
哪种方法不好,因为您不知道其他参数的类型,也不知道它们有多少个。要了解这些事情,您应该像使用类似printf的函数那样做,解析字符串中表示参数存在的特定标记以及参数的类型,或者至少使用参数的const变量计数器。您可以进一步宏观分析,参数的计数是自动的。
更新:
您实际上并不需要 stdarg在C中使用可变参数功能,因为这是内置功能。C预处理器还可以扩展可变参数(尽管可能并非在所有版本中)。库stdarg提供了那些有用的宏,但是您也可以自己实现它们。请注意,不使用标准库几乎总是错误的事情。只需获取第一个(引用)变量的地址,将其增大指针的大小,即可获得下一个参数的地址(大概)。就像是:
#include <stdio.h>
#define INIT_VARARG(x,ref) void* x = &ref
#define GET_NEXT_VARARG(ptr,type) (*((type* )(ptr+=sizeof(ptr))))
void func (int ref, ...) // ref must be the number of int args passed.
{
INIT_VARARG(ptr,ref);
int i;
for(i = 0; i < ref; i++)
{
printf("[%i]\n", GET_NEXT_VARARG(ptr, int));
}
}
int main (void)
{
func(3, 10, 15, 20);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您只能将其用于实验目的。良好,安全且设计良好的C代码不应包含此类宏,而应使用stdarg。