1.5编写一个简单的项目程序
这个项目将向读者演示在本章学到的C++语言和项目管理的特性。该项目将使用若干源代码文件,以便读者可以了解到依赖项的作用,以及构建工具是如何管理源代码变更的。这个项目非常简单,它将要求你输入名字,然后在命令行上打印输出名字以及相关的时间和日期。
1.5.1项目结构
该项目包含3个函数:main函数,它会调用其他另外两个函数print-name和print_time。它们分别位于3个独立的源代码文件中,因为main函数将调用位于其他源代码文件中的两个函数,这意味着main函数源代码文件中必须包含这些函数的原型声明。在本示例中,这意味着引用每个文件的头文件。该项目还会使用一个预编译头文件,这表示存在一个源代码文件和一个头文件。总之,项目中将包含3个头文件和4个源代码文件。
1.5.2创建预编译头文件
该代码将使用C++标准库的流对象进行信息的输入和输出,因此我们将使用iostream)头文件。代码中将使用C++的字符串类型处理信息输入,因此还将使用string头文件。最后,它会访问C运行时库的time和date函数,因此代码中还将用到ctime头文件。这些都是标准的头文件,我们在进行程序开发时无需对它们进行修改,因此它们是预编译的理想目标。
在VisualStudio中创建一个C++头文件,然后在其中添加如下代码:
includestringinclude""
将其另存为,我们将需要为这个项目创建一个makefile,因此在新建文件对话框中,选择文本文件作为文件类型。添加以下规则来构建预编译头文件:
::/EHsc//Ycutilsh
将它另存为文件名为"makefile."的文件,注意要在文件末尾加一个句点(.)符号。因为我们是以文本文件的形式创建该文件的,VisualStudio将自动为它添加一个txt文件后缀,但是因为我们不希望使用该文件后缀,所以需要添加一个句点以表明该文件无后缀名。其中第一行表示和依赖于特定的源代码文件和头文件。第二行(以一个制表符作为前缀)告知编译器去编译C++文件,但是不调用链接器,同时还告知编译器将预编译代码保存到文件中。该命令将创建和
文件,即声明的两个目标。
当make实用程序发现有两个目标时,默认的动作(当目标和依赖项之间使用单个冒号时)是为每个目标都调用一次命令(你可以使用宏来决定哪个目标需要被构建)。这意味着相同的编译器命令将执行两次。这是我们不希望看到的,因为两个目标是通过调用一次命令构建的。双冒号:是一个变通方案,它告知nmake不要采用为每个目标调用命令的行为。最终的结果就是,当make程序调用命令一次,并生成了文件,然后它会尝试生成文件,不过它发现该文件已经被生成了,所以不需要再次调用命令。
现在测试输出结果。在命令行中,导航到项目文件夹下,输入nmake命令。
如果没有提供makefile的名称,程序维护工具将自动使用名为makefile的文件(如果你希望使用一个其他名字的makefile,可以使用/f开关并指定文件名):
C:\BeginningC++\Chapter_01\CodenmakeMicrosoft(R)(C)/EHsc//(R)C/C++OptimizingCompilerVersion19,00.24210forx86Copyright(C)
查看文件目录列表,以确认和文件是否已经被创建。
1.5.3创建主文件
现在创建一个C++源代码文件并添加如下代码:
include"name,h"include""include""#include""voidprint_time(){std::time_tnow=std::time(nullptr);std::cout",thetimeanddateare"std::ctime(now)std::l;}
sta::time和std::gmtime这两个函数是C函数,并且std:time_t是一个C类型,所有这些都是通过C++标准库获得的。std:time函数获取的时间是1970年1月1日午夜以来的秒数。该函数会返回一个std::time_t类型的值,即一个64位整数。如果用户通过指针传递变量在存储中的存储位置,则该函数可以将上述整数值拷贝到另外一个变量中。
在这个示例中,我们不需要这个工具,因此我们传递一个C++的nullptr给该函数,以声明不需要执。行拷贝操作。
接下来,我们需要将秒数转换成包含时间和日期的字符格式,以方便用户理解。这也是std::ctime函数的主要用途,它会接收一个指向保存秒数变量的指针作为参数。变量now保存了秒数,运算符用于获取变量的内存地址。第4章将详细介绍变量和指针的细节。std::ctime函数会返回一个字符串,不过我们还没有为该字符分配任何内存,也不应该尝试为该字符串分配内存。std:ctime函数创建了一个静态分配内存缓冲区,它将被运行在当前执行线程的所有代码共享使用。每次在相同执行线程上调用std:ctime函数时,使用的内存地址是一样的。不过内存中的内容可能会发生变化。
此函数说明检查帮助手册,查看谁负责分配和释放内存是非常重要的。第4章将详细介绍分配内存的细
节。
从std:ctime返回的字符被打印输出到控制台,并且是通过调用若干次运算符对输出结果进行格式化的。
:/EHsc//
保存该文件并运行make工具,然后确认该构建过程是否生成了目标文件。
1.5.6构建可执行文件
现在我们已经拥有了项目所需的所有对象文件,因此下一个任务是将它们链接到一起。为此,将下列代码添加到makefile文件顶部
time_:/out:$@$**
这里的目标是可执行文件,并且依赖项是4个对象文件。命令行中为了构建可执行文件会调用链接器并使用特殊的语法。标识符$@会被make工具解析为使用目标,所以/out开关实际的内容是
/out:time_。标识符$**会被make工具解析为使用所有依赖项,因此所有依赖项都将被链接。
保存该文件并运行make程序。用户将发现只有链接器被调用,并且它将链接所有对象文件继而创建可执行文件。
最后,添加一条规则来清理项目。提供一种机制移除编译过程中生成的文件,只保留源代码文件,从而保持项目结构的整洁是一个非常好的习惯。在链接对象文件的代码行之后,添加如下代码:
time_:/out:@$**clean:@_
clean任务是一个伪目标,实际上并没有生成文件,因此也不存在依赖项。这说明了make程序的个特性,如果调用mmake工具,并指定目标名称,那么该程序将只生成该目标。如果没有声明目标,那么该程序将生成makefile提及的第一个目标,在这种情况下是time_
clean伪目标包含3个命令:第一个命令会将"Cleaningtheproject.打印输出到控制台,标识符e会告知命令行不要将该命令打印输出到控制台;第二个和第三个命令会调用命令行工具de1删除文件。现在可以在命令行上输入mmakeclean命令清理项目,然后确认项目目录下是否只包含头文件、源代码文件和makefile文件。
1.5.7测试代码
再次运行make程序,以便构建可执行文件。在命令行中,可以通过输入time_test命令运行示例程序。你将被要求输入姓名;执行此操作,然后按回车"键,此时将发现自己的名字、当前时间和日期被打印输出到控制台上:
C:Beginning_C++Chapter_01time_testYourfirstname?RichardRichard,thetimeanddateareTueSep619:32:232016
1.5.8修改项目
现在读者对基本的项目结构有所了解,通过makefile,你可以对文件进行修改,并确保重新构建项目时,只对发生变更的文件进行编译。为了说明这一点,将修改中的print_name函数,以更客气的方式询问你的姓名。修改函数体中第一行代码,比如下列代码中加粗显示的代码行:
voidprint_name(){std::cout"Pleasetypeyourfirstnameandpress[Enter]";std;;stringname;
保存该文件,然后运行make工具。这一次只有源代码文件被编译,生成的文件会与已有的对象文件链接到一起。
现在修改头文件,并在其中添加一个注释信息:
//更客气的版本voidprint_name();
构建该项目。读者发现了什么?这一次,有两个源代码文件被编译,即和。并且它们与已有的对象文件链接到一起,从而创建了可执行文件。为了细究这两个文件被编译的原因,可以查看makefile中的依赖项规则。唯一发生变更的文件是,并且该文件的名字出现在了和依赖项列表上,因此这两个文件被重新构建。由于这两个文件出现在了time_的依赖项列表上,所以该可执行文件也将被重新构建。
本文节选自《C++编程自学宝典》
本书旨在通过全面细致的内容和代码示例,带领读者更加全方位地认识C++语言。全书内容共计10章,由浅入深地介绍了C++的各项特性,包括C++语法、数据类型、指针、函数、类、面向对象特性、标准库容器、字符串、诊断和调试等。本书涵盖了C++11规范及相关的C++标准库,是全面学习C++编程的合适之选。
版权声明:本站所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请举报,一经查实,本站将立刻删除。