是不是将所有参数传递给函数都不好?

Dra*_*ton 6 c function

我一直在尝试使用下面的源代码"动态调用函数".在使用仅接受前两个参数的testing_function成功测试此代码之后,我在第三个中添加并在调用函数时决定"不提供参数".我注意到,当我这样做时,第三个参数的值不是(必然)0,而是一个"随机"值,我不知道它的起源.

问题如下:

  • 这些价值来源于哪里?
  • 另外,如何将参数传递给函数?
  • 不传递参数是不好的做法吗?
  • 是否可以为函数参数的添加做好准备,而无需使用函数重新编译代码?(例如:动态加载的库的函数获得了一个可接受的参数,但是不会重新编译使用该函数的代码).

源代码的前言如下:

我正在使用Linux运行,使用GCC 4.6.3编译/调用链接器,并且在使用此代码时不会收到编译/链接警告/错误.此代码执行'完美'.我打电话给gcc如下:

gcc -x c -ansi -o (output file) (input file, .c suffix)
Run Code Online (Sandbox Code Playgroud)

源代码如下:

#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!"));
}
Run Code Online (Sandbox Code Playgroud)

zwo*_*wol 7

这些价值来源于哪里?

通常它们将是来自先前操作的存储器或寄存器.

另外,如何将参数传递给函数?

这取决于平台ABI; 通常在指定的一组寄存器中或在"堆栈指针"的固定偏移处.

不传递参数是不好的做法吗?

是.它触发"未定义的行为"; 编译器有权在您执行该程序时崩溃您的程序,或者更糟.

是否可以为函数参数的添加做好准备,而无需使用函数重新编译代码?(例如:动态加载的库的函数获得了一个可接受的参数,但是不会重新编译使用该函数的代码).

不会.每当您更改属于库ABI的C函数的参数列表时,您还必须更改其名称.(你可以在源代码API中隐藏这些技巧,但它们都是改变函数名称的基本策略.)

在C++中,当然更改的参数列表是一个新的重载,但是由编译器为您更改名称来实现.


Zan*_*ynx 2

函数参数的传递取决于编译器使用的 C ABI。这可能意味着它们在堆栈或寄存器或两者的组合中传递。我相信 32 位 Intel 系统通常在堆栈中传递,而 64 位 Intel 系统主要在寄存器中传递,溢出发生在堆栈上。

未传递参数的随机值从何而来?它们来自应该保存该值的寄存器或堆栈位置。被调用的函数不知道参数没有被传递,所以无论如何它都会提取它。

如果所有参数都应该位于堆栈上,这可能会导致严重问题,因为该函数将提取比现有更多的堆栈项。在最坏的情况下,它将擦除函数返回地址。

使用寄存器时,除了随机值之外,这不是什么大问题。

从上述信息中,您应该能够了解到它不受支持,您不应该这样做,并且通常它不会工作。

有效是变量参数列表。例如,printf是否可以。POSIX 函数也是如此open()。开放声明如下所示:

extern int open (__const char *__file, int __oflag, ...);
Run Code Online (Sandbox Code Playgroud)

看到三点了吗?这声明了一个变量参数列表。它可以包含 0 到任意数量的参数。它们可以使用特殊函数来访问。知道需要多少个参数的唯一方法是前面的参数之一。在 的情况下open()oflag值。对于printf()格式字符串。