在main
之前的C编写函数声明中似乎是多余的。
我不想使用这些方法:
if __name__ == '__main__':
main()
C的实现方式是什么?
#include <stdio.h>
void printHello(void);
int main(void)
{
printHello();
}
void printHello(void)
{
printf("Hello World\n");
}
环境: 我使用的make脚本在哈佛大学的cs50云IDE中使用带有其他检查的clang。 IDE设置了c99版本的语言,没有函数声明就无法编译。
我的测试: 仅使用clang仍然错误相同;使用GCC实际上只编译了警告。
GCC为什么起作用? GCC看到一个没有前面声明的函数调用,它假定该函数返回int并进行了编译。(c99之前的行为)
已解决:
c99定义消除了隐式键入,因此必须在使用前声明所有函数。
没有等效的功能:if __name__ == '__main__':
用C语言编写,用于在文件顶部写入main()。
感谢您的帮助John Bode;现在很有意义。
答案 0 :(得分:1)
在C语言中,每个程序的入口都是main
函数 1 ,并且不需要专门对其进行标记-只需将其定义为
int main( void ) { ... }
如果您不使用任何命令行参数,或者
int main( int argc, char **argv ) { ... }
如果是。
在C中,所有功能至少必须在使用前声明 。在较旧的C版本中,如果编译器看到的函数调用没有前面的声明,则它假定函数返回了int
。但是,该语言定义的1999年版本消除了隐式键入,因此所有功能必须都必须在使用前声明。
函数定义被视为声明,并且可以在源文件中以任何顺序定义。我总是建议,如果它们都在同一个翻译单元 2 中,则应在调用方之前定义被调用函数,例如
#include <stdio.h>
int foo( int x ) { return 2 * x; }
int bar( int x ) { return foo( x ) * 3; }
int main( void )
{
printf ( "bar( %d ) = %d\n" , 2, bar(2) );
return 0;
}
这意味着您的代码在底部的main
处向后读取,但是IME使得代码易于维护,因为您不必弄乱单独的声明。
如果在另一个转换单元(源文件)中定义了函数,则将需要单独的声明。我们通常通过将这些声明收集在单独的 header文件中,然后在必要时#include
-对该文件进行访问来实现此目的:
bar.h:
#ifndef BAR_H // include guard - not required, but good practice.
#define BAR_H // Keeps the contents of the file from being processed more than once in a translation unit
int foo( int ); // only need the type of the argument in a declaration
int bar( int );
#endif
bar.c:
#include "bar.h"
int foo( int x ) { return 2 * x; }
int bar( int x ) { return foo( x ) * 3; }
main.c
#include <stdio.h>
#include "bar.h"
int main( void )
{
printf( "bar( %d ) = %d\n", 2, bar(2) );
return 0;
}
如何将功能划分为单独的源文件和头文件取决于项目。
您可能已经注意到我在stdio.h
周围使用尖括号,在bar.h
周围使用引号。不同的定界符指示在哪里可以找到包含文件的编译器的不同搜索路径。引号表示先搜索当前工作目录,然后搜索标准搜索路径中的其他目录(用尖括号指示)。
答案 1 :(得分:0)
在C语言中,调用的第一个函数必须具有以下原型:
int main(int argc, char* argv[])
其中argc
是参数的数量,而argv[]
是包含参数的char *数组
如果您对参数无所谓,也可以在以下声明main:
int main()
答案 2 :(得分:0)
您确实需要做一个前向声明(如果您想在文件的开头保留main),因为此代码将被编译而不执行。当编译器逐行编译时,它在到达函数之前就不会知道该函数的签名。
人们习惯于在文件底部开发更重要的功能。
但是编译如何工作?
编译实际上分两步进行。
1)Gcc(或您使用的任何文件)将为您拥有的每个文件制作一个预编译版本。
2)它将所有这些预编译的文件链接到可执行文件或库文件等中。
现在您知道这一点,您可以了解其工作原理:
答案 3 :(得分:0)
python文件也是python模块。如果要在模块的命名空间中使用某些内容,通常会导入它。很明显,在将模块视为可执行文件(用于测试等)时,通常使用if __name__ == “__main__”
构造。使用C之类的编译语言,可以通过在main
文件中调用.c
来实现。
答案 4 :(得分:0)
接受的答案包含严重错误。 C编译器不不知道文件中的每个顶级声明。他们只知道顶级声明,这些声明在文本上显示在当前正在处理的声明上方。用数据定义很容易证明这一点:
// This code will not compile
const char *const strings[] = { sThis, sThat };
static const char sThis[] = "this";
static const char sThat[] = "that";
由于上面的片段,您会遇到严重错误,因为在编译器处理sThis
时sThat
和strings
还不可用。将strings
的定义移到sThis
和sThat
的定义之下是修复该错误的唯一方法。
但是,对于函数,“隐式函数声明”的遗留功能使问题变得混乱。在大多数C编译器的默认模式下,此命令可能会编译并带有警告:
#include <stdio.h>
int main(void)
{
printHello();
}
void printHello(void)
{
printf("Hello World\n");
}
因为编译器在调用表达式中首次遇到printHello
时会猜测其类型签名。但是,猜测总是错误的:一个隐式声明的函数总是被理解为接受数量不确定的参数并返回 int
,这从根本上就是您想要的。编译器会欣然接受
#include <stdio.h>
int main(void)
{
return printHello(1, "frobozz", 3.14159)
+ printHello(2.1828);
}
void printHello(void)
{
printf("Hello World\n");
}
即使这显然是胡说八道。
用C语言执行OP想要做的正确方法是使用OP不喜欢的“冗余”前向声明:
#include <stdio.h>
static void printHello(void);
int main(void)
{
printHello();
}
static void printHello(void)
{
printf("Hello World\n");
}
如果要将printHello
的定义放在printHello
的下面,这是与编译器通信的唯一方法,main
不带任何参数,不返回任何内容。 / p>