无我炼 待到樱花绚烂时
魂淡
关注数: 143 粉丝数: 185 发帖数: 19,804 关注贴吧数: 107
【C++】IO流 一、C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来进行输入与输出。如下图所示: 对输入输出缓冲区的理解: 1.可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植的程序。 2.可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”。 二、流是什么 “流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据( 其单位可以是bit,byte,packet )的抽象描述。 C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。 它的特性是:有序连续、具有方向性 为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:http://tieba.baidu.com/mo/q/checkurl?url=https%3A%2F%2Fblog.csdn.net%2Fqq_55401402%2Farticle%2Fdetails%2F139400973&urlrefer=2bacf40f3913a1b4746ca19832fd3993
头文件 一般来说,为了避免重复定义问题,头文件主要用于声明,但并非绝对不能定义,下面分别说明不同情况:头文件主要用于声明的原因及常见声明内容原因在 C++ 的编译过程中,多个源文件(.cpp 文件)可能会包含同一个头文件。如果头文件中存在定义,就会导致每个包含该头文件的源文件对应的翻译单元都有该定义,从而在链接时引发重复定义错误。常见声明内容 函数声明:告知编译器函数的名称、参数类型和返回值类型,但不包含函数体。例如: cpp// example.hint add(int a, int b); // 函数声明 全局变量声明:使用 extern 关键字声明全局变量,表明该变量在其他地方定义。例如: cpp// global.hextern int globalVar; // 全局变量声明 类声明:定义类的结构,但不实现类的成员函数(成员函数的实现可以放在 .cpp 文件中)。例如: cpp// person.hclass Person {public: Person(const std::string& name, int age); void introduce();private: std::string name; int age;};头文件中可以进行定义的特殊情况1. 内联函数定义内联函数可以在头文件中定义。因为内联函数在编译时会直接将函数体嵌入到调用处,而不是像普通函数那样进行函数调用,所以即使多个翻译单元包含同一个内联函数定义,也不会出现重复定义问题。例如:cpp// math.hinline int max(int a, int b) { return a > b ? a : b;}2. 模板定义模板(包括函数模板和类模板)的定义通常也放在头文件中。这是因为模板在实例化时需要知道其完整的定义,编译器需要根据具体的模板参数生成对应的代码。例如:cpp// vector_template.htemplate<typename T>class Vector {public: Vector(); void push_back(const T& value);private: T* data; size_t size; size_t capacity;};template<typename T>Vector<T>::Vector() : data(nullptr), size(0), capacity(0) {}template<typename T>void Vector<T>::push_back(const T& value) { // 实现代码}3. const 和 constexpr 变量定义const 和 constexpr 变量具有内部链接属性,即它们的作用域仅限于当前翻译单元。因此,在头文件中定义 const 或 constexpr 变量不会导致重复定义问题。例如:cpp// constants.hconst int MAX_VALUE = 100;constexpr double PI = 3.1415926;综上所述,头文件主要用于声明,但在特定情况下(如内联函数、模板、const 和 constexpr 变量)也可以进行定义。
翻译单元 Translation Unit 在 C++ 中,翻译单元(Translation Unit)是一个重要的概念,它和编译过程紧密相关,下面为你详细介绍:定义一个翻译单元是指经过预处理器处理后得到的单个输入文件,简单来说,通常可以认为一个 .cpp 文件加上它所 #include 的所有头文件内容构成一个翻译单元。具体解释当编译器对代码进行编译时,它并不是将整个项目一次性处理,而是以翻译单元为单位逐个进行编译。每个翻译单元会被独立编译成一个目标文件(.obj 文件,在 Windows 系统中)或 .o 文件(在类 Unix 系统中),最后再由链接器将这些目标文件链接成一个可执行文件或库文件。示例说明假设我们有以下几个文件:main.cppcpp#include "example.h"int main() { exampleFunction(); return 0;}example.hcpp#ifndef EXAMPLE_H#define EXAMPLE_Hvoid exampleFunction();#endifexample.cppcpp#include "example.h"#include void exampleFunction() { std::cout << "This is an example function." << std::endl;}在这个示例中,存在两个翻译单元: 第一个翻译单元由 main.cpp 和 example.h 组合而成。预处理器会将 #include "example.h" 指令替换为 example.h 文件的实际内容,然后编译器对这个组合后的内容进行编译,生成 main.obj(Windows)或 main.o(类 Unix)。 第二个翻译单元由 example.cpp 和 example.h 以及 头文件的内容组成。同样,预处理器会处理所有的 #include 指令,编译器再对处理后的内容进行编译,生成 example.obj(Windows)或 example.o(类 Unix)。 最后,链接器会将 main.obj 和 example.obj 链接在一起,生成最终的可执行文件。
自动变量和栈 自动变量定义 在 C 和 C++ 中,自动变量(Automatic Variable)是一种存储类别的变量。当你在函数或代码块(如if、for、while语句块)内部定义变量时,如果没有显式指定存储类别(如static、extern等),那么这些变量默认就是自动变量。自动变量使用auto关键字来声明,不过在现代 C++ 中,auto更多地用于类型推导,而自动变量的声明往往省略auto关键字。示例 收起cpp#include <iostream>void func() { // 自动变量,省略了 auto 关键字 int num = 10; std::cout << "Value of num: " << num << std::endl;}int main() { func(); return 0;}特点 作用域:自动变量的作用域局限于定义它的函数或代码块内部,离开这个范围后就无法访问。 生命周期:自动变量的生命周期从定义它的语句开始,到所在函数或代码块执行结束时结束。每次进入该函数或代码块时,自动变量都会被重新创建;离开时,自动变量所占用的内存会被释放。 自动变量与栈的关系 自动变量通常存储在栈内存中。栈是一种后进先出(LIFO)的数据结构,在程序运行时,栈用于管理函数调用和局部变量的存储。 存储分配:当程序进入一个函数或代码块时,系统会在栈上为该函数或代码块内的自动变量分配内存空间。这些变量按照定义的顺序依次压入栈中。 内存释放:当函数或代码块执行结束时,系统会自动从栈中弹出这些自动变量所占用的内存空间,实现内存的自动回收。这个过程是由编译器自动完成的,无需程序员手动干预。 函数与栈的关系 函数本身的代码并不会放在栈里面,函数代码存储在程序的代码段(也称为文本段),这是用于存储可执行指令的区域。不过,函数调用过程与栈密切相关: 函数调用栈帧:每次调用一个函数时,系统会在栈上为该函数创建一个栈帧(Stack Frame)。栈帧包含了函数的局部变量(包括自动变量)、函数的参数、返回地址(函数调用结束后要返回的位置)等信息。 调用和返回过程:当调用一个函数时,当前函数的执行上下文(如寄存器的值)会被保存,新函数的栈帧会被压入栈中,程序跳转到新函数的代码处执行。当函数执行结束时,其栈帧会从栈中弹出,恢复之前保存的执行上下文,程序返回到调用点继续执行。 示例代码展示函数调用栈帧的工作原理: 收起cpp#include <iostream>void func2(int param) { int localVar = param + 5; std::cout << "Value in func2: " << localVar << std::endl;}void func1() { int num = 10; func2(num); std::cout << "Back in func1" << std::endl;}int main() { func1(); std::cout << "Back in main" << std::endl; return 0;} 在这个示例中,main函数调用func1,func1又调用func2。每次函数调用时,都会在栈上创建新的栈帧;函数返回时,相应的栈帧会被销毁。
1 下一页