news 2026/9/14 9:29:17

C++和标准库速成(一)——HelloWorld和名称空间

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++和标准库速成(一)——HelloWorld和名称空间

目录

  • 1. 引言
  • 1. 简单小程序"Hello World"
    • 1.1 模块导入
    • 1.2 预处理指令
      • 1.2.1 简介
      • 1.2.2 常用的预处理指令
    • 1.3 main()函数
    • 1.4 输入输出流
      • 1.4.1 输出流
      • 1.4.2 转义字符
      • 1.4.3 输入流
  • 2. 名称空间
    • 2.1 定义名称空间
    • 2.2 using指令
    • 2.3 嵌套名称空间
    • 2.4 名称空间别名
  • 参考

1. 引言

C++20的标准库模块目前还没有正式得到编译器的支持,而MSVC中已经存在了对标准库模块的实验性支持。需要安装适用于v143生成工具的C++模块,并且将普通控制台应用项目属性C/C++下的所有选项中的启用实验性的C++标准库模块改为是。

vs18只需要安装完默认的“使用C++的桌面开发"就行了,然后在新建的控制台应用中点击项目,选择最后一个xxx和属性,点击C/C++的所有选项,将生成ISO C++23的标准库模块改为是。

1. 简单小程序"Hello World"

importstd.core;// vs18需要改为import std;intmain(){std::cout<<"Hello, World!"<<std::endl;return0;}

1.1 模块导入

C++20中最重要的新特性之一就是对模块的支持,用来替代之前的头文件机制。如果你想要使用某个模块中的功能,则需要导入这个模块,可以通过一条import声明做到。如import std.core;
如果你的编译器还不支持模块,只需要简单地将import声明替换为#include预处理指令。

1.2 预处理指令

1.2.1 简介

如果你的编译器还不支持C++20的模块,需要编写如下的预处理指令:#include <iostream>
简单来说,生成一个C++程序共有3个步骤。首先,代码经过预处理器,预处理器会识别代码中的元信息。其次,代码被编译或转换为计算机可识别的目标文件。最后,独立的目标文件被连接在一起生成一个应用程序。
预处理指令以#字符开始,前面实例中的#include <iostream>就是一条预处理指令。在此例中,include指令告诉预处理器:提取<iostream>头文件中的所有内容并提供给当前文件。
头文件最常见的用途是声明在其他地方定义的函数,函数声明会通知编译器如何调用这个函数,并声明函数中参数的个数和类型,以及函数的返回类型;函数定义包含这个函数的实际代码。在C++20引入模块之前,声明通常放在扩展名为.h的文件中,称为头文件,其定义通常包含在扩展名为.cpp的文件中,称为源文件。有了模块,我们不再需要将声明与定义分离,但是之前的写法仍然可以使用。
注意:
1. 在C中,标准库头文件的名称通常以.h结尾,不使用名称空间。
2. 在C++中,标准库头文件的名称省略了.h后缀,所有文件都在std名称空间和std的子名称空间中定义。
3. C中的标准库头文件在C++中依然存在,但使用以下两个版本:
3.1 不使用.h后缀,改成前缀c,这是推荐使用的版本,这些头文件将内容放在std名称空间中。
3.2 使用.h后缀,这是旧版本,这些版本不适用名称空间。

1.2.2 常用的预处理指令

预处理指令功能常见用法
#include [file]将指定的文件插入代码中指令所在的位置几乎总是用来包含头文件,使代码可使用在其他位置定义的功能
#define [id] [value]每个指定的标识符都被替换成指定的值在C中,常用来定义常数值或宏。C++提供了常数和大多数宏类型的更好机制。在C++使用宏有风险
#ifdef [id]
#endif
#ifndef [id]
#endif
ifdef(if defined)块和ifndef(if not defined)块中的代码被有条件地包含或舍弃,这取决于是否使用#define定义了特定的标识符经常用来防止循环包含。每个头文件都以#ifndef开头,以保证某个标识符还未被定义,然后用一条#define指令定义该标识符。头文件以#endif结束,这样这个头文件不会被多次包含
#pragma [xyz]xyz因编译器而异。如果在预处理期间执行到这一指令,通常会显示一条警告或错误信息参见该表之后的举例

下面是使用预处理指令避免重复包含的一个实例:

#ifndefMYHEADER_H#defineMYHEADER_H// ... the contents of this header file#endif

如果编译器支持#pragma once指令,可采用以下方法重写上面的代码。

#pragmaonce// ... the contents of this header file

1.3 main()函数

main()函数是程序的入口。main函数返回一个int值以指示程序的最终执行状态。在main()函数中可以忽略显式的return语句,这种情况下会自动返回0.main()函数要么没有参数,要么具有两个参数,如下所示。
int main(int argc, char* argv[])
argc给出了传递给程序的实参数目,argv包含了这些实参。注意argv[0]可能是程序的名称,也可能是空字符串,所以不应使用它。应当使用特定于平台的功能检索程序名。最重要的是,实际参数从索引1开始

1.4 输入输出流

1.4.1 输出流

基本的输入输出非常简单,可将输出流想象为针对数据的洗衣滑槽,放入其中的任何内容都可以被正确地输出。std::cout就是对应于用户控制台或标准输出的滑槽,此外还有其他滑槽,包括用于输出错误信息的std::cerr。<<运算符将数据放入滑槽,在前面的示例中,引号中的文本字符串被送到标准输出。输出流可在一行代码中连续输出多个不同类型的数据,如下面的代码所示。
std::cout << "There are " << 219 << " ways I love you." << std::endl;
从C++20开始,推荐的写法是使用std::format(),定义在中,用来格式化字符串。如std::cout << std::format("There are {} ways I love you.", 219) << std::endl;。std::endl代表序列的结尾。当输出流遇到std::endl时,就会将已送入滑槽的所有内容输出并转移到下一行。

1.4.2 转义字符

表明一行结尾的另一种方法是使用\n字符,\n字符是一个转义字符,这是一个换行符。转义字符可以在任何被引用的文本字符串中使用。

转义字符含义
\n换行:将光标移到下一行的开头
\r回车:将光标移到本行的开头
\t制表符
\反斜杠字符
"引号

警告:请记住endl会在流中插入新的一行,并且将当前缓冲区中的所有内容刷出滑槽。不建议过度地使用endl,例如在循环中使用,这会影响程序的性能。另一方面,在流中插入\n也会插入新的一行,但不会自动刷新缓冲区。

1.4.3 输入流

流还可用于接收用户的输入,最简单的方式是在输入流中使用>>运算符。std::cin输入流接受用户的键盘输入。示例如下:

intvalue;std::cin>>value:

需要慎重对待用户输入,因为永远都不会知道用户会输入什么类型的数据。
如果你拥有C的背景知识但初次接触C++,你可能想了解过去使用的、可靠的printf()和scanf()现在究竟是什么情况。尽管C++中仍然可以使用这些函数,但强烈建议你改用format()和流库,主要原因是printf()和scanf()未提供类型安全。

2. 名称空间

2.1 定义名称空间

名称空间用来处理不同代码段之间的名称冲突问题。例如,你某天编写了一段代码,其中有一个名为foo()的函数。某天,你决定用第三库,其中也有一个foo()函数。编译器无法判断你的代码要使用哪个版本的foo()函数。库函数的名称无法改变,而改变自己的函数名称又会感觉到痛苦。
在此类情况下使用名称空间,从而指定定义名称的环境。为将某段代码加入名称空间,可用namespace块将其包含。示例如下:

namespacemycode{voidfoo(){std::cout<<"foo() called in the mycode namespace"<<std::endl;}}

将你编写的foo()版本放到名称空间mycode后,这个函数就与第三方库提供的foo()函数区分开来。为调用启用了名称空间的foo()版本,需要使用::在函数名称之前给出名称空间,::称为作用域解析运算符
mycode::foo();

2.2 using指令

mycode名称空间中的任何代码都可调用该名称空间内的代码,而不需要显式说明该名称空间。隐式的名称空间可使代码清晰并易于阅读。可使用using指令避免预先指明名称空间。这个指令通知编译器,后面的代码将使用指定名称空间中的名称。示例如下:

usingnamespacemycode;intmain(){foo();// Implies mycode::foo();}

一个源文件中可包含多条using指令,这种方法虽然便捷,但注意不要过度使用。极端情况下,如果你使用了已知的所有名称空间,实际上就是完全取消了名称空间。如果使用了两个同名的名称空间,将再次出现名称冲突问题。另外,应该知道代码在哪个名称空间内运行,这样就不会无意中调用错误版本的函数。
可以使用using指令引用名称空间内的特定项。例如,想要只使用std名称空间中的cout,可以使用如下的using声明:
using std::cout;
后面的代码可以使用cout而不需要预先指明这个名称空间,但仍然需要显式说明std名称空间中的其他项。
警告:切勿在全局作用域的头文件中使用using指令或using声明,否则添加你的头文件的每个人都必须使用它。将其放在较小的作用域,例如名称空间或类作用域中,是可以的,甚至是在文件头部。将using指令或using声明放在模块接口文件中也是不错的选择,只要你不将它导出

2.3 嵌套名称空间

嵌套的名称空间,即将一个名称空间放在另一个名称空间中。各个名称空间之间由双冒号隔开,示例如下:

namespaceMyLibraries::Networking::FTP{/*...*/}

这种紧凑写法是在C++17之后才得到支持的,在C++17之前,必须按如下方式使用嵌套的名称空间。

namespaceMyLibraries{namespaceNetworking{namespaceFTP{/*...*/}}}

2.4 名称空间别名

可使用名称空间别名,为另一个名称空间指定一个更简短的新名称。示例如下

namespaceMyFTP=MyLibraries::Networking::FTP;

参考

[比] 马克·格雷戈勒著 程序喵大人 惠惠 墨梵 译 C++20高级编程(第五版)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 9:27:14

Laravel + Dcat Admin 实战:送水站后台的中间件、状态机与队列设计

简介&#xff1a;这是一份基于PHP Laravel与Dcat Admin构建的送水后台管理系统源码包&#xff0c;面向掌握PHP基础、想了解主流框架整合开发或需要快速搭建管理后台的开发者。系统实现了订单管理、用户管理、配送员管理等完整业务模块&#xff0c;代码中清晰展示了路由定义、中…

作者头像 李华
网站建设 2026/9/14 9:25:45

Python Flask+百度地图+机器学习大模型:车辆管理可视化全链路解析

题目里这些关键词——Python、Flask、百度地图、可视化、大模型、机器学习——第一次看到的人会觉得这是不是把热门技术全堆了一遍&#xff0c;但真正动手拆解之后你会发现&#xff0c;它其实是一个特别典型的“数据采集 → 后端服务 → 可视化展示 → 智能分析”全链路项目。我…

作者头像 李华
网站建设 2026/9/14 9:25:22

AI边缘推理重构光模块三温测试流程

1. 项目概述&#xff1a;光模块三温测试的“时间黑洞”正在被AI算力击穿光模块三温测试——这个在光通信产线里人人皱眉、个个叹气的环节&#xff0c;过去十年几乎没变过&#xff1a;把待测模块放进温箱&#xff0c;-40℃稳住30分钟&#xff0c;常温再30分钟&#xff0c;85℃再…

作者头像 李华
网站建设 2026/9/14 9:25:10

如何在 wasm32 serverless 环境中使用 axum 路由处理单请求

如何在 wasm32 serverless 环境中使用 axum 路由处理单请求 【免费下载链接】axum HTTP routing and request-handling library for Rust that focuses on ergonomics and modularity 项目地址: https://gitcode.com/GitHub_Trending/ax/axum 大多数 Rust 后端经验是“起…

作者头像 李华
网站建设 2026/9/14 9:23:41

时域自相关法估计DSSS码片周期:原理、MATLAB实现与参数边界

简介&#xff1a;面向DSSS/BPSK信号分析与伪码周期估计的MATLAB代码包&#xff0c;适用无线通信、扩频通信方向的本科生与工程师快速上手时域自相关法。资源围绕完整实验链路组织&#xff0c;共8个m文件、压缩包仅6KB&#xff0c;包含m_sequence.m用于生成PN码、BPSK1.m与de_BP…

作者头像 李华