我一直在使用下面的源代码试验“动态调用函数”。在使用仅接受前两个参数的 testing_function 成功测试此代码后,我添加了第三个参数并决定在调用该函数时“不提供参数”。我注意到当我这样做时,第三个参数的值不是(必然)0,而是一个我不知道其来源的“随机”值。
问题如下:
- 这些值(value)观来自哪里?
- 此外,如何将参数传递给函数?
- 不传递参数是不好的做法吗?
- 是否可以在不重新编译使用函数的代码的情况下为添加函数参数做好准备? (例如:一个动态加载的库函数获得了一个可接受的参数,但使用该函数的代码不会被重新编译)。
源代码前言如下:
我正在使用 Linux 运行,使用 GCC 4.6.3 编译/调用链接器,并且在使用此代码时没有收到任何编译/链接警告/错误。此代码执行“完美”。我像下面这样调用 gcc:
gcc -x c -ansi -o (output file) (input file, .c suffix)
源码如下:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
/* Function for testing. */
int testing_function(char* something, char* somethingelse, int somethingadditional)
{
int alt_errno = errno;
if ((something != NULL)&&(somethingelse != NULL))
{
errno = 0;
if (fprintf(stdout, "testing_function(\"%s\", \"%s\", %d);\n", something, somethingelse, somethingadditional) <= 0)
{
if (errno != 0)
{
int alt_alt_errno = errno;
perror("fprintf(stdout, \"testing_function(\\\"%%s\\\", \\\"%%s\\\", %%d);\\n\", something, somethingelse, somethingadditional)");
errno = alt_errno;
return alt_alt_errno;
}
else
{
errno = ENOSYS;
perror("fprintf(stdout, \"testing_function(\\\"%%s\\\", \\\"%%s\\\", %%d);\\n\", something, somethingelse, somethingadditional)");
errno = alt_errno;
return ENOSYS;
}
}
else
{
errno = alt_errno;
return 0;
}
}
else
{
errno = ENOSYS;
perror("testing_function(char* something, char* somethingelse, int somethingadditional)");
errno = alt_errno;
return ENOSYS;
}
}
/* Main function. */
int main(int argc, char** argv)
{
int (*function)(char*, char*);
*(void**) (&function) = testing_function;
exit(function("Hello", "world!"));
}
最佳答案
这些值来自哪里?
通常它们将是以前操作产生的内存或寄存器垃圾。
另外,如何将参数传递给函数?
取决于平台ABI;通常在一组指定的寄存器中或在“堆栈指针”的固定偏移处。
不传递参数是不好的做法吗?
是的。它触发“未定义的行为”;编译器有权在您执行此操作时使您的程序崩溃,或者更糟。
是否可以在不重新编译使用函数的代码的情况下为添加函数参数做好准备? (例如:一个动态加载的库函数获得了一个可接受的参数,但使用该函数的代码不会被重新编译)。
没有。每当您更改作为库 ABI 一部分的 C 函数的参数列表时,您必须也更改其名称。 (您可以使用一些技巧将其隐藏在源代码级 API 中,但它们都是对更改函数名称这一基本策略的伪装。)
在 C++ 中,更改的参数列表当然是一个新的重载,但它是由编译器为您更改名称来实现的。
关于c - 不是将所有参数传递给函数不好吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16553113/