C 参数被传递给函数

C 参数被传递给函数,c,linux,C,Linux,考虑以下来源: main.c 你好 #include<stdio.h> void print_hello(){ printf("Hello world\n"); } #包括 void print_hello(){ printf(“Hello world\n”); } 编译和链接gcc-o hello.cmain.c后,工作正常,但我预计会出现错误。因为main.c中的print\u hello和hello.c中的print\u hello的签名是不同的。为什么工作正常?您

考虑以下来源: main.c

你好

#include<stdio.h>
void print_hello(){
    printf("Hello world\n");
}
#包括
void print_hello(){
printf(“Hello world\n”);
}

编译和链接
gcc-o hello.cmain.c
后,工作正常,但我预计会出现错误。因为
main.c
中的
print\u hello
hello.c
中的
print\u hello
的签名是不同的。为什么工作正常?

您没有告诉编译器文件
main.c
中的
print\u hello()
函数是什么样子的。如果您有一个头文件
hello.h
,例如:

#ifndef HELLO_H_INCLUDED
#define HELLO_H_INCLUDED

extern void print_hello(void);

#endif
在每个文件的顶部包含“hello.h”,然后在编译器使用的
main.c

中错误使用
print\u hello()
会得到相关的编译器警告,允许将额外的参数传递到被调用函数,而不会产生额外的效果。这在C的调用约定之间是典型的,因为它在此类约定中支持变量参数列表(如printf、scanf等)

  • 参数的传递顺序是第一个参数最接近堆栈顶部(如果所有参数都放在堆栈上)或在等效寄存器中,其他参数按顺序放置
  • 调用方知道使用的堆栈大小,并在函数调用后恢复堆栈指针
在这种情况下,通常将其命名为“cdecl”(可选地,带有1或2个下划线)

这样的约定可以容忍额外的参数,但肯定不能容忍被调用函数随后使用的未指定参数;后一种情况导致参数中出现垃圾

一般来说,不应该利用这些运行时特性,但在某些情况下,它是有用的


为了防止函数使用和定义之间的不匹配,应该对两者使用相同的声明。通常,在声明或调用此函数的所有源中都包含相同的头文件。

除了其他解释之外,假设在Linux上更好:

您应该使用
gcc-Wall-std=c99
进行编译,以获取所有警告(
-Wall
),并告诉编译器您要遵守哪个标准(
-std=c99
)。通过这些设置,您会收到警告:

  main.c: In function 'main':
  main.c:2:5: warning: implicit declaration of function 'print_hello' 
              [-Wimplicit-function-declaration]
  print_hello("str");
 ^
至于为什么没有给出错误,它们只能由链接器在时间上给出(
ld
,由
gcc
调用)。Unix和Linux链接器(来自GNU)只与名称一起工作:每个函数(更一般地说,每个链接符号)都有一个名称(并且对象文件和可执行文件都在其中,它们定义了名称的表示方式,等等……)如果两个名称相同,则链接器通过使它们引用相同的地址来解析(参见Levine)。因此,由于
main.o
hello.o
中的两个名称(或符号)都是
print\u hello
,因此它们是链接在一起的。用于查询ELF对象或可执行文件中的名称。当然,在运行时发生的是,但是(和)的约定启用了您期望的行为。重要的是ELF不会在对象文件中保留键入或签名元数据


<> P> C++ C++,有点不同:编译器正在转换函数名(在ELF <代码> *.O/COD>文件中的文件不是简单的C++源名称),所以链接器会看到不同的名称(并且会失败)。请给我一个链接,指向有关此约定的
C
标准条款。由于缺少这些约定,我无法给你一个指向C标准中约定的链接。C标准是为比寄存器机器、基于堆栈的机器等更广泛的条件而设计的,它唯一规定的是,如果向所有使用它的源提供函数声明,则不会出现奇怪的效果。所有公约细节都是特定于平台的,尽管其中大多数原则相似。
  main.c: In function 'main':
  main.c:2:5: warning: implicit declaration of function 'print_hello' 
              [-Wimplicit-function-declaration]
  print_hello("str");
 ^