3

我正在学习 C,在开始学习 C++ 作为我的第一门编译语言之后,我决定“回归基础”并学习 C。

关于每种语言处理函数的方式,我有两个问题。

首先,为什么 C “不关心”函数定义的范围,而 C++ 呢?

例如,

int main()
{
    donothing();
    return 0;
}

void donothing() { }

以上不会在 C++ 编译器中编译,而在 C 编译器中会编译。为什么是这样?C++ 不是主要是 C 的扩展,并且应该主要是“向后兼容”吗?

其次,我发现的书(链接到 pdf)似乎没有说明 main 函数的返回类型。我环顾四周,发现了其他书籍和网站,这些通常也没有为 main 函数指定返回类型。如果我尝试编译一个没有为 main 指定返回类型的程序,它在 C 编译器中编译得很好(尽管有一些警告),但它不能在 C++ 编译器中编译。再说一遍,这是为什么呢?总是将返回类型指定为整数而不是忽略它是更好的风格吗?

感谢您的帮助,顺便说一句,如果有人能推荐一本我应该买的更好的书,那就太好了!

4

6 回答 6

6

首先,为什么 C “不关心”函数定义的范围,而 C++ 呢?

实际上,C 确实在乎。只是 C89 允许隐式声明的函数,int并从用法中推断其返回类型及其参数。C99 不再允许这样做。

因此,在您的示例中,就好像您已将原型声明为

int dosomething();

隐式返回类型也是如此:int在 C89 中推断缺少的返回类型,但不是在 C99 中。编译您的代码gcc -std=c99 -pedantic-errors会产生类似于以下内容的内容:

main.c: In function 'main':
main.c:2:5: error: implicit declaration of function 'donothing' [-Wimplicit-function-declaration]
main.c: At top level:
main.c:5:6: error: conflicting types for 'donothing'
main.c:2:5: note: previous implicit declaration of 'donothing' was her

作为记录,这是我使用的代码:

int main() {
    donothing();
    return 0;
}
void donothing() { }
于 2012-10-05T09:36:13.517 回答
3

这是因为 C++ 支持可选参数。当 C++ 看到donothing();它无法判断是否donothing是:

void donothing(void);

或者

void donothing(int j = 0);

在这两种情况下,它必须传递不同的参数。这也是因为 C++ 的类型比 C 更强。

于 2012-10-05T09:35:05.757 回答
2

上面的他不会在 C++ 编译器中编译,而它将在 C 编译器中编译。为什么是这样?

因为 C++ 要求函数的声明(或定义)在调用点的范围内。

C++ 不只是 C 的扩展吗?

不完全是。它最初是基于一组 C 扩展,它引用 C 标准(有一些修改)来定义 C 标准头文件的内容。C++“语言本身”类似于 C,但不是它的延伸。

并且应该主要是“向后兼容”?

强调“大部分”。大多数 C 功能都在 C++ 中可用,并且许多被删除的功能是为了使 C++ 成为比 C 更严格的类型语言。但没有特别期望 C 代码将编译为 C++。即使是这样,它也并不总是具有相同的含义。

我环顾四周,发现了其他书籍和网站,这些通常也没有为 main 函数指定返回类型

C 和 C++ 标准一直说main返回int.

在 C89 中,如果您省略函数的返回类型,则假定它是int. C++ 和 C99 都缺少这种隐式 int 返回类型,但许多 C 教程书籍和教程(以及编译器和代码)仍然使用 C89 标准。

C 允许实现接受其他返回类型,但不允许可移植程序要求它们。两种语言都有一个“独立实现”的概念,它可以以任何它喜欢的方式定义程序的进入和退出——同样,因为这是特定于实现的,它不适合 C 的一般教学。

IMO,即使您要使用 C89 编译器,也值得将您的代码编写为有效的 C99(特别是如果您有 C99 编译器可用于检查它)。C99 中删除的功能在某种程度上被认为是有害的。甚至尝试编写 C 和 C++ 的代码都是不值得的,除非在用于语言之间互操作的头文件中。

我决定“回归基础”并学习 C。

您不应该将 C 视为 C++ 的先决条件或“基本形式”,因为它不是。不过,它是一种更简单的语言,用于高级编程的功能较少。这通常被 C 的用户引用为 C 的优势。C++ 的用户也将其称为 C++ 的优势。有时,这些用户是出于不同目的使用这些语言的同一个人。

C 中的典型编码风格与 C++ 中的典型编码风格不同,因此在 C 中学习某些基础知识可能比在 C++ 中更容易。使用 C++ 学习低级编程是可能的,而当你这样做时编写的代码最终可能会或可能不会看起来很像 C 代码。

因此,您在学习 C 时学到的东西可能会或可能不会影响您编写 C++ 的方式。如果是这样,那可能会更好,也可能不会。

于 2012-10-05T09:55:22.570 回答
2
int main() {
    donothing();
    return 0;
}
void donothing() { } 

很好的最小工作示例。

在 gcc 4.2.1 中,上述代码会收到关于void donothing()默认编译器设置的冲突类型的警告。这就是 C89 标准所说的与此类问题有关的内容。使用 clang,上面的代码在void donothing(). C99 标准更严格一些。

编译 C++ 代码时启用警告并设置为高阈值是个好主意。这在 C 中变得更加重要。编译时启用警告并将隐式函数声明视为错误。

void donothing(void);C 和 C++ 之间的另一个区别:在 C++ 中,声明之间没有区别,而在 C 中这两者之间void donothing();存在巨大差异。第一个是不带参数的函数。后者是具有未指定调用序列的函数。

永远不要donothing()用来指定不带参数的函数。编译器别无选择,只能接受donothing(1,2,3)这种形式。donothing(1,2,3)当函数声明为 时,它知道拒绝void donothing(void)

于 2012-10-05T10:37:40.397 回答
1

C++ 故意改变了这些规则,使 C++ 成为一种更安全的语言。

C.1.4第 5 条:表达式[diff.expr]
5.2.2
更改:不允许函数的隐式声明
理由: C++ 的类型安全性质。
对原始特征的影响:删除语义上定义明确的特征。注意:原始特征在 ISO C 中被标记为“过时”。
转换难度:句法转换。产生显式函数声明的工具在商业上相当普遍。
用途广泛:常见。

您可以在此Draft C++ 标准的附录 C 中找到其他类似的更改

于 2012-10-05T09:43:47.887 回答
0

C++ 不只是 C 的扩展吗?

不,如果你认为 C++ 是“C with Classes”,那你就大错特错了。虽然严格来说,大多数有效的 C 都是有效的 C++,但实际上没有好的C 就是好的C++。现实情况是,好的 C++ 代码与您所看到的好的 C 代码大不相同。

首先,为什么 C “不关心”函数定义的范围,而 C++ 呢?

从本质上讲,因为不执行与 C++ 相同的规则使得在 C 中这样做非常不安全,事实上,任何理智的人都不应该这样做。C99 加强了这一点,以及隐式 int 和 C 语言中的其他缺陷。

于 2012-10-05T12:40:34.510 回答