在C语言中,删除#include <stdio.h>是否正确?

3
如果我在C语言中使用printfscanfputs或其他一些函数,而没有写一个include行,这能被视为未指定或未定义的行为吗?
我记得,C语言根本不需要原型声明,但建议使用它们以允许编译器在调用时进行类型转换。至今,printf和其他类似函数的原型仍不是必需的,不确定自定义函数是否需要。
注:本问题与https://codegolf.stackexchange.com/a/55989/32091评论中的讨论有关。

3
“C didn't require prototype declaration at all” - 这是指古老/中世纪的 C 语言。自 1989 年起,声明是必需的(特别是在未将可变参数函数声明为可变参数函数时调用它是未定义行为)。但你为什么要这样做呢? - The Paramagnetic Croissant
1
@TheParamagneticCroissant,问题中有一个代码高尔夫的链接。删除这一行将使代码减少18个字符。此外,当一些解决方案有它而其他解决方案没有时,这很奇怪。 - Qwertiy
1
如果你真的需要缩短程序或编写自复制程序,这当然是可行的。但无论如何,你都应该始终包含头文件。 - mtszkw
2
@Qwertiy Codepad 没有显示任何警告。但是,在我的电脑上使用 -Wall -pedantic 编译它会产生很多警告。因此,gcc 确实会发出警告。 - Enzo Ferber
1
@MichałSzydłowski,我在询问有关cstdio具体函数的问题。不确定,但我认为它们具有某些特殊行为,而且正是这个unclude可以被跳过,而不是C中的任何include。 - Qwertiy
显示剩余8条评论
4个回答

2

对于专业发展来说,不可以。

对于代码高尔夫(codegolfing)来说,可以。

如果您不声明一个函数,编译器会自动生成一个函数,该函数可能与其实际声明相匹配,也可能不匹配。如果不匹配,它可能会导致段错误或软件错误。 gcc 也会在这种情况下发出警告。


这个问题不是关于专业发展的 - 在那种情况下我同意你的观点。但你绝对确定stdio中的函数不是根据标准而言的特例吗? - Qwertiy
@Qwertiy 我不排除这种可能性,但我认为这很不可行,因为这是一种语言问题,与标准库无关。 - peterh
我会即兴猜测,因为标准只是在谈论环境必须提供这些函数,但系统和编译器都可以被认为是环境,所以两者都提供它,但操作系统具有更高的优先级。(但是,如果您查看例如gcc的安装目录,您将找到其自己的实现作为头文件,这是为了那种情况,但它可能会或不会警告,因为它也可以被视为环境,并且标准规定其功能必须是:...." 但这只是一个即兴的假设。 - dhein
1
不,这是不可以的。对于没有原型的函数调用的参数将被提升,除非函数以期望进行这种提升的方式定义,否则函数看到的参数将与调用者传递的参数不匹配,除非所有参数都不需要提升。由于库函数期望参数被提升,因此在调用代码中省略头文件是不可以的。 - Andrew Henle

2
在C语言中去掉#include不是正确的做法。如果您使用了像printf这样的stdio.h函数,一定要包含它。
随着C99的推出,C已经移除了隐式声明,并且需要包含头文件。唯一的替代方法是有一个可见的带原型的声明,例如printf。
此外,即使在C具有隐式声明的情况下,对于可变参数函数,隐式声明也是不可以的;因此,在C89中不添加stdio.h头文件,也没有可见的原型声明(例如printf),是未定义的行为。

它被移除了吗? - Qwertiy
@Zaibis 在我的回答中,我写了“唯一的其他选择是为 printf 有一个可见的原型声明。” - ouah
@ouah - 虽然这可能有点过于追求精确,但可变参数函数使用传递参数的机制与没有原型的函数相同:参数提升。事实上,如果将C语言中的可变参数语法开发为主要驱动器之一,使得现有库函数(例如具有可选“mode”参数的open()函数)可以拥有一个原型,也不足为奇。 - Andrew Henle

1

stdio.h中有您想要使用的函数的明确声明,如果它是C++编译器(例如g++),那么这些东西是被禁止的。 由于C++需要所有函数的明确声明,但任何适当的C编译器都会创建这些函数的隐式声明,将代码编译为目标文件,并在与标准库链接时找到那些函数的定义,意外地匹配隐式声明,可能会导致gcc给出警告。

因此,如果您正在编写希望易于维护和阅读的软件,放弃它不是一个选择,但是对于快速原型设计或代码挑战,这可能并不是那么重要。


“可能并不那么重要”?在LP64环境中调用诸如malloc()之类的基本函数而没有包含正确的头文件…… - Andrew Henle

0

在技术上,你可以在许多情况下跳过#include。但是对于某些函数,编译器无法在没有原型的情况下生成正确的函数调用。例如,如果参数是double并且你输入0 - 在有原型的情况下,它将被转换并存储为堆栈中的double值,否则将会是int,这将产生错误的计算。


我理解这个。但标准中有没有明确规定呢? - Qwertiy
C语言的第一个标准规定,如果没有原型,函数被假定为 int func( void )(如果我没记错的话)。也就是说,只有在没有参数时才没有原型。 - i486

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接