函数声明对C编程至关重要吗?

函数声明对C编程至关重要吗?,c,gcc,assembly,compilation,nasm,C,Gcc,Assembly,Compilation,Nasm,我曾经认为,在使用之前,我们应该声明一个在另一个文件中定义的函数,但最近,由于编程的经验,我改变了我的思维方式。对于三个文件,C和ASM: main.c kernel.asm 另一个。asm 编撰 结果 在我看来,如果我想在main.c中使用函数myprint,我应该事先使用extern声明它,因为myprint是在另一个文件中定义的,但结果正好相反。正如上面显示的那样。如果我添加行extern myprint,我将得到一个错误。然而,如果没有这个声明,我将得到正确的结果。而且,我没有在main

我曾经认为,在使用之前,我们应该声明一个在另一个文件中定义的函数,但最近,由于编程的经验,我改变了我的思维方式。对于三个文件,
C
ASM

main.c

kernel.asm

另一个。asm

编撰

结果


在我看来,如果我想在main.c中使用函数
myprint
,我应该事先使用
extern
声明它,因为
myprint
是在另一个文件中定义的,但结果正好相反。正如上面显示的那样。如果我添加行
extern myprint
,我将得到一个错误。然而,如果没有这个声明,我将得到正确的结果。而且,我没有在main.c中定义函数
myprint
,为什么我可以使用该函数?我不应该事先声明吗?

当您在没有原型的情况下调用函数时,编译器会对该函数的参数进行一些假设和猜测。所以您应该声明它,但将其声明为函数:

void myprint(const char *, const char *); /* Or whatever. */

当然,您可以使用函数
myprint
,尽管它在main.c中没有定义,但没有错误。这是因为编译器在创建对象文件时,会针对所创建的对象文件中的符号
myprint
填充空值

仅在链接阶段,二进制文件中的所有位置都会用函数的实际地址替换此空值。链接器在所有对象文件中引用符号表,并用实际地址解析符号(无论在何处引用)

当然,您将看到
-Werror-Wall
选项对
gcc
的警告/错误。尽管如此,您可以通过使用
objdump
获得更多信息,如下所示:

objdump -D main.o | less

希望这有助于澄清您的疑问。

如果您使用
gcc-c-g-W-Wall-pedantic-o main.o main.c
编译,会怎么样?那么GCC对此有什么看法呢?尝试使用extern myprint()告诉编译器这是一个函数。非常感谢!这真的很详细。但我仍然有一点我不能理解。我在
gcc
中添加了
-Werror-Wall
选项,并在main.c:
void myprint(char[],int)中添加了函数声明,没有错误。但是,对于在
main.c
之外定义的函数,我是否应该在声明的开头添加
extern
,例如
extern void myprint(char[],int)?谢谢!但是为什么不在声明的开头添加
extern
?无论如何,该函数是在其他文件中定义的。@MarkZar“extern”对于函数是隐式的。由于编译器在这种情况下所做的修改而导致的错误通常是非常严重的。。。
[section .text]
global myprint
myprint:
    mov edx, [esp + 8]
    mov ecx, [esp + 4]
    mov ebx, 1
    mov eax, 4
    int 0x80
    ret
nasm -f elf another.asm -o another.o
gcc -c -g main.c -o main.o
nasm -f elf kernel.asm -o kernel.o
ld -o final main.o kernel.o another.o
./final 
a simple test
void myprint(const char *, const char *); /* Or whatever. */
objdump -D main.o | less