C++基础学习

本文探讨了C++中预处理指令的使用,包括#ifndef/endif防止头文件重复定义,#pragma预处理命令,常量指针与指针常量的区别,extern关键字在函数链接性和变量作用范围中的应用,以及函数指针的定义与用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.预处理指令 标识符

预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
注意:预处理指令是在编译器进行编译之前进行的操作.预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。可见预处理过程先于编译器对源代码进行处理。

1.1 C++头文件为什么要加#ifndef #define #endif
#ifndef 在头文件中的作用
在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件时,就会出现大量“重定义”的错误。在头文件中使用#ifndef #define #endif能避免头文件的重定义。
例如:要编写头文件test.h
在头文件开头写上两行:

#ifndef _TEST_H(标识符)
#define _TEST_H                 //一般是文件名的大写
头文件结尾写上一行:
#endif
这里的“标识符”是自己定义的,但每一个文件里的该“标识符A”必须是唯一的。
为了方便辨认,以及宏名常用大写表示,所以常将“标识符”写成“_头文件名大写_H”。
实际上这里的“标识符A”的名称与头文件名称没有什么必然联系。

这样一个工程文件里同时包含两个test.h时,就不会出现重定义的错误了。为什么呢?
当第一次包含test.h时,由于没有定义_TEST_H,条件为真,这样就会包含(执行)#ifndef _TEST_H和#endif之间的代码,当第二次包含test.h时前面一次已经定义了_TEST_H,条件为假,#ifndef _TEST_H和#endif之间的代码也就不会再次被包含,这样就避免了重定义了。实际上默认的头文件都会包含,比如 stdio.h

1.2 #ifdef 语句使用方法

2. C语言#pragma预处理

在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma 指令对每个编译器给出了一个方法,在保持与C 和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。

其格式一般为:
   #pragma para

#pragma预处理命令详解

3. 常量指针和指针常量

如何区分/如何读?看const的位置,const在最前面,就读常量指针,另一种就读指针常量。
常量指针:
const在int前,说明修饰的是int类型,说明指向的值不能变,即指向一个常量,但是指向可以变,即地址可以改变。

int a,b;
const int *p=&a //常量指针
//那么分为一下两种操作
*p=9;//操作错误
p=&b;//操作成功

指针常量:
const在指针p前,说明修饰的是指针,说明指针指向不能变,即指针指向的地址不能被修改,但是该地址里的内容可以被修改。

int a,b;
int * const p=&a //指针常量
//那么分为一下两种操作
*p=9;//操作成功
p=&b;//操作错误
const int * const b = &a;//指向常量的指针常量

常量指针和指针常量

4.C++中关于函数的extern链接性以及extern关键字

C++中extern关键字主要有三种作用,即声明变量的链接性、函数的链接性、以及语言的链接性。所谓的链接性(linkage)是指名称如何在不同的编译单元间共享。与其相应的是作用域(scope),它描述的是名称在一个编译单元的多大范围内可见。

(i)变量的链接性:由于C++中变量具有单定义规则(one definiton rule)(只能被定义一次),那么在同一个工程的其他文件中,如果要想使用一个已经定义的变量,只能使用声明(declaration)。一个全局变量的默认链接性是只在本文件可见,在另外一个文件中可以使用extern来声明这个变量,表示该变量已经在它处定义,从而使得该变量在“变量声明”所在的文件同样可见,达到共享的目的。

(ii)函数的链接性:默认情况下函数的链接性是外部的,即可以在文件间共享。可以使用extern来指出这一点,即该函数是在另外一个文件中定义的,不过这是可选的。但是如果用static来修饰函数的话,那么其链接性就是内部的。 如果用static修饰函数的链接性,必须同时给出函数原型以及定义。

//func.cpp
#include <iostream>
void func()
{
    std::cout<<"Location:func.cpp->func()"<<std::endl;
}
//main.cpp
#include <iostream>
void func();//or extern void func();
int main()
{
    func();
    return 0;
}

在func.cpp中定义了函数func(),要在main.cpp中使用这个函数的话,必须在main.cpp中先声明这个函数。注意这里func.cpp和main.cpp是两个独立的编译单元,通过在main.cpp中声明函数,来实现函数在文件间的共享。在编译时必须同时包含这两个cpp文件。 其次,可以使用static修饰函数,来限制函数的链接性。 如果在上面的函数中将func.cpp中的func()函数用static来修饰,同时给出函数的实现,此时该函数无法被其他文件调用即

static void func()
{
    std::cout<<"Location:func.cpp->func()"<<endl;
}

(iii)语言的链接性:在C语言中函数是不能重载的,因此在编译后,一个函数名对应于一个翻译后的符号名,例如 test(int),对应于_test。但是C++是可以重载的,因此函数经编译器翻译后的名称会有所不同。例如会将test(int),对应于_test_i。但是可以使用extern “C”来告诉编译器不要按照C++默认的方式翻译,而使用类似于C的方式翻译。
参考文档链接

5.函数指针

(i)函数指针定义格式:

函数返回值类型 (* 指针变量名) (函数参数列表);
int(*p)(int, int);

这个语句就定义了一个指向函数的指针变量 p。首先它是一个指针变量,所以要有一个“*”,即(*p);其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;
后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。
所以合起来这个语句的意思就是:定义了一个指针变量 p,该指针变量可以指向返回
值类型为 int 型,且有两个整型参数的函数。p 的类型为 int(*)(int,int)。
(ii)用法示例:

# include <stdio.h>
int Max(int, int);  //函数声明
int main(void)
{
    int(*func)(int, int);  //定义一个函数指针func
    int a, b, c;
    func = Max;  //把函数Max赋给指针变量func, 使func指向Max函数
    printf("please enter a and b:");
    scanf("%d%d", &a, &b);
    c = (*func)(a, b);  //通过函数指针func调用Max函数
    printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
    return 0;
}
int Max(int x, int y)  //定义Max函数
{
    int z;
    if (x > y)
    {
        return x;
    }
    return y;
}

(iii)使用typedef定义函数指针:

typedef int (PTypeFun1)(int, int); // 声明一个函数类型
typedef int (*PTypeFun2)(int, int); // 声明一个函数指针类型
int (*padd)(int, int); // 传统形式,定义一个函数指针变量

以上三种形式都可以正确的使用函数指针,那么使用 typedef 来定义函数指针有什么好处呢?
首先,使用 typedef 定义函数指针,代码看起来更简洁,也更不容易出错。
其次,当函数指针作为其它函数的参数,特别是作为返回值时,直接使用的函数指针无法编译。
参考文档链接

6.C++中变量的作用范围(可见范围)

(i)局部变量: 作用域为当前代码块,即{}中。在代码块外部不可见

(ii)静态变量局部静态变量,即在代码块中声明的静态变量,作用域为当前代码块,超过该代码块则不可见; 类静态成员变量,作用域为当前类,超出类范围则不可见;全局静态变量,不在类中也不在代码块中。该变量作用范围在当前文件

(iii)全局变量:全局变量作用范围为整个模块\工程,如果其他文件中有定义同名变量,链接器会报符号重定义,如果确实想在整个模块中使用一个变量。则需要在一个cpp中定义,其他引用的地方需要extern修饰声明使用该变量:

a.cpp定义int _a = 0;   b.cpp中使用: extern int _a; _a = 1;

任何全局变量,静态\非静态,都不应该被定义在.h文件中,因为.h文件会被其他文件包含,如果是非静态全局变量,在链接时会直接报符号重定义,因为.h被cpp包含一次,就会多一次定义。 如果是静态全局变量,则比较隐晦,连接器不会报错,但是包含该.h的cpp都会有一个该变量的定义,结果是各自使用各自的,除非清楚这样的作用,否则绝不应该使用。建议永远不要再.h中定义全局变量,无论是否静态。
参考文档连接

7.C++中引用(&)的用法和拷贝/赋值函数的区别

参考文档链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GJ_WL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值