你好, 欢迎回来｡
在这节课中, 我只想复习一些常见的编译器和警告｡
我们讨论了一些常见的c问题｡
但是有时候, 当编译器试图告诉你这些错误时, 你甚至不知道你的程序中有这些错误｡
编译器错误和警告对于新的程序员来说往往非常晦涩难懂｡
他们可能会告诉你, 你错过了一个分号, 但它说, 无法到达的结束语句｡
对于新人来说, 他们可能甚至不知道这意味着什么｡
因此,
随着时间的推移, 编写大量代码和破译一些编译器警告需要大量的实践｡
但在那之前我想给你提个醒｡
你们在上节课中看到的一些常见问题,
我将描述一些编译器警告和错误, 以及它会说些什么｡
告诉你要理解编译器告诉你的东西是非常非常重要的｡
如果编译器告诉你错误, 但是你不理解这个错误,
那么你需要花更长的时间来修复这个代码｡
但如果您看到错误, 并且确切地知道它在说什么,
则可以立即修复它｡
我记得, 当我第一次开始编程的时候, 我会在实验室里, 我会错过一个分号,
一个很常见的东西｡ 编译器会告诉我, 我少了一个分号,
但我不知道, 它只会说, 语句结尾不可达, 我会想, 这是什么意思,
什么是语句. 我会很困惑｡
这就是为什么我想给予你一些提示, 告诉你编译器实际上想告诉你什么｡
所以很难理解编译器在抱怨什么｡
要破译这些消息有时候是非常令人困惑的｡
因此, 您需要了解这些编译器错误, 以便修复它们, 这是非常基本的｡
编译器为您完成了一半的工作｡
它检查语法, 告诉你到底哪里错了,
所以你应该利用它｡
但有时很难准确理解它在说什么, 特别是如果你是新来的,
你不明白一些术语｡
编译器决定如何翻译程序员未在代码中编写的代码｡
这对程序和编译器都很方便, 这样就可以写得更简洁｡
只有专业程序员才能利用此功能｡
所以我要告诉你的是, 当你编译的时候, 你应该总是使用dash
wall选项｡
这会打开一切｡
所以有时候更高级的功能是你可以去掉一些东西, 让翻译更有效｡
但是当你添加它的时候, 你会导致程序以不同的方式编译｡
因此, 您的代码中可能会出现您不知道的警告｡
所以我告诉你的原因是你总是想用一个特定的选项来编译, 这个选项就是dash wall选项｡
默认情况下, 这在代码块中是打开的｡
这将通知您编译器正在执行您不知道的操作的所有情况｡
它还将打开所有警告,
给予你提供大量信息, 这是非常有用的编译器选项｡
一旦启用了该选项, 就可以尝试帮助您更好地理解编译器告诉您的一些内容｡
编译器会给你们看两种类型的问题｡
一个是错误｡
这实际上会阻止程序的创建｡
您有语法错误, 无法编译程式｡
未重新创建任何可执行工作, 并且｡
通常, 当您看到来自编译器的错误时, 您总是希望关注第一个错误｡
这是最可靠的错误, 因为其他一些错误可能是第一个错误的结果｡
因此, 请始终关注第一个错误｡ 首先修复顶部的错误,
然后再次编译, 看看其他错误是否消失｡
警告｡
警告是编译器在特殊情况下显示的消息, 在特殊情况下检测到某种类型的异常｡
它们不是致命错误｡ 因此将创建可执行文件｡
但你还是应该去弥补｡
警告是有原因的｡
您可能做得不正确, 或者将来可能会导致问题｡
因此, 您希望始终修复所有警告｡
通过使用dash
wall选项进行编译, 在消除所有警告之前, 您不会认为程序正确｡
因此编译不会失败｡
这就是为什么我告诉你使用这个选项, 以及看到编译器正在进行的一切｡
所以你会遇到一些最常见的编译器消息, 这将直接与我们前面提到的一些最常见的c问题相关｡
如果一个变量未声明, 您将首先使用此函数看到该消息变量未声明｡
这是最常见的一种, 通常更容易检测到｡
然后它也会在此消息之前显示符号｡
它基本上会说你试图使用这个变量, 但是你从来没有真正声明过它｡
我们知道, 当你声明一个变量时, 你指定了数据类型｡
你不能只是给不存在的变量签名｡
一个警告隐式声明的函数, 这与函数声明有关｡
当你试图调用一个函数, 但是这个函数没有任何相关的实现时｡
您没有包含标头, 或者您没有声明它｡ 所以它不知道它在哪里,
也不知道函数是如何声明的, 不知道参数, 不知道返回值.
没有关于函数本身的信息？
要解决这个问题, 请始终在顶部声明一个函数原型｡
另一个警告是, 警告控制到达了非空函数的末尾,
当函数被定义为返回一个非空的结果, 但函数中没有包含return语句时,
就会发生这种情况.
所以你忘了归还数据｡
函数定义不正确, 您必须在函数声明之前删除数据类型,
或者您忘记添加该return语句｡
必须更改其中一个才能修复此警告｡
但你明白这是一个警告｡
你仍然可以在那里编译, 但是这可能会在你的程序中真正引起剪切问题｡
如果你期望一个函数返回一些东西, 而它没有, 那么你想修复你的警告, 未使用的变量,
另一个常见的警告｡
当声明变量时, 编译器会打印此变量, 但它从未使用过｡
如果不使用变量, 就不应该声明该变量,
因此请删除该声明｡
我在做一些演示的时候经常会得到这些, 因为我在变量中留下了我从来没有使用过的变量｡
或者当我在演示如何声明一个变量,
然后我编译它来向你展示编译后的结果时, 我会得到一个警告, 说它从未被使用过｡
所以这没关系, 因为我在演示一些东西｡
但是如果你的变量没有被使用, 就把它们去掉｡ 不需要申报｡
未定义的指涉｡ 这发生在链接阶段｡
所以记住编译器或编译阶段, 它会编译｡
首先, 它将运行预处理程序, 然后它将生成目标文件,
然后它将把这些目标文件链接在一起, 形成一个完整的程序｡
因此,
在链接阶段, 它需要解析任何外部依赖项｡
特别是你调用的任何函数, 它们都需要在某个地方实现｡
所以如果它没有目标文件, 就会出现这个问题｡
您正在尝试调用一个函数, 但我们没有它的代码｡
所以你要么确保你链接到这个文件｡
通常链接会为你发生, 但在GCC中, 你可以只做破折号l选项来添加链接文件｡
所以如果你在数学头文件中使用一个函数, 但是你没有链接到数学对象文件, 你会得到这个错误｡
如果你有用户定义的, 并且你没有包括一个c源文件,
也会发生这种情况｡
所以你有多个c源文件｡
其中一个c源文件正在实现这个函数｡
另一个c源文件正在包括头文件并调用它,
但你从未编译过的另一个c源文件中有这个实现, 你会看到这个错误｡
所以一定要引入源文件,
如果你需要的话, 一定要引入任何标准库源文件, 通常你不需要这样做｡
另一个常见错误是当的型别恩怨时｡
这是当你实际上定义或声明了一个函数原型, 然后当你去实现它的时候,
它和你声明它的方式不一样｡
例如, 原型有一个结果类型, 参数的名称是括号, 然后是分号｡
然后,
当您定义实现时, 就会有一个不同的实际函数头｡
返回类型不同, 或者参数数目不同｡
这就是说, 你有一个函数声明｡
然后当你在下面实施它时, 情况完全不同｡
所以这是不匹配的｡
这实际上会在这条线上告诉你, 冲突出现在之前的定义中,
导致了矛盾｡
所以在实现中, 通常是显示行的地方,
因为通常你在顶部声明函数｡
运行时错误｡ 运行时错误是代码中的问题,
它发生在运行程序时, 而不是编译程序时｡
所以这些通常是崩溃或者是非致命错误, 比如数组越界之类的.
就是程序运行的时候, 出现了某种逻辑错误.
因此, 当检测到运行时错误时, c程序的执行可能会突然终止并崩溃,
这是它无法处理的｡ 就像我说的, 内存损坏了｡
超出界限的错误通常会导致程序崩溃｡
通常, 您会看到分段错误｡
而分段错误并不能告诉你任何事情｡
所以通常你要做的是进一步诊断这个问题, 就是查看调用栈,
就像我之前提到的, 程序崩溃时, 逐行步进, 看看是哪一行导致了崩溃｡
如果有一个核心文件, 你可以得到调用栈, 我前面提到过｡
然后从调用堆栈中, 您可以看到哪一行崩溃了｡
或者更好的方法是, 运行调试器, 一行一行地执行, 然后当你执行一行的时候,
调试器, 你会看到程序崩溃, 你可以通过这种方式来识别它｡
这些只是关于编译器错误､ 警告和消息以及如何解释它们的一些提示｡
网上其实有链接｡
或者如果你用谷歌搜索, 它会告诉你每一个编译器错误和警告, 它会给予一个定义,
说明为什么会产生它, 以及本质上是什么问题｡
因为同样, 这些编译错误可能非常隐蔽｡
甚至还有一个词表示遥不可及的控制｡
从这个描述中你可以知道, 除非你有经验, 这意味着, 你永远不会从函数中返回东西.
但是如果你这样做了,
当你有编译器错误而你不理解编译器的时候, 最好的方法之一就是在你的程序中找到并修复问题, 谷歌一下｡
通常会发生堆栈溢出｡
它会告诉你, 嘿, 这是你的错误, 这是你解决它的方法｡
直到今天我还是这样｡
我已经用c编程15年了,
但还是有一些时候我遇到了一些事情, 我想这到底是什么意思｡
我会在谷歌上搜索一下, 我会把编译器放在引号里,
它会告诉我到底发生了什么｡
Stack Overflow是一个非常非常好的网站｡
而且它确实可以在调试过程中保存大量的时间｡
当您看到编译器或警告时, 不要只是猜测｡
编译器试图告诉你一些事情, 它会准确地指出发生了什么｡
所以如果你理解了它, 你就能更快地解决你的问题｡
如果你对它不熟悉, 去堆栈溢出或者去一个描述它们的网站, 你可以用那种方法来破译它｡
我希望这对你有帮助｡ -谢谢—谢谢