跳转到内容
新建笔记

变量

说明

在C语言中,当我们谈论“执行”时,通常是指执行代码,而不是执行变量。变量本身不执行任何操作,但是它们可以存储数据,这些数据可以被程序中的代码访问和修改。

当提到在 main 函数之外声明的变量时,我们通常指的是全局变量或静态变量。这些变量的初始化和使用发生在程序的执行过程中,但它们并不“执行”。以下是它们在程序执行过程中的行为:

  1. 全局变量(Global Variables):

    • 全局变量是在所有函数之外声明的变量,它们在程序的整个执行期间都是可见和可用的。
    • 全局变量在程序启动时初始化(如果提供了初始化器),并且在 main 函数执行之前就已经存在。
    • 程序中的任何函数都可以访问和修改全局变量(除非它们被声明为 static,这将限制它们的作用域仅在定义它们的文件内)。
  2. 静态变量(Static Variables):

    • 在函数内部声明的静态变量在函数调用之间保持其值。即使函数返回,静态变量的值也不会丢失。
    • 静态变量在第一次调用包含它们的函数时初始化,并且在 main 函数执行之前就已经初始化。
  3. 局部变量(Local Variables):

    • 局部变量是在函数内部声明的变量,它们仅在该函数的作用域内可见。
    • 局部变量在函数被调用时创建,并在函数返回时销毁。
  4. 执行时机:

    • 全局变量和静态变量的初始化是在 main 函数执行之前完成的。确切地说,它们是在程序的启动阶段,也就是在调用 main 函数之前初始化的。
    • 局部变量的创建和初始化是在它们所在函数被调用时进行的。
  5. 代码执行:

    • 程序的执行始于 main 函数,但全局变量和静态变量在 main 函数执行之前就已经存在并可能已经被初始化。
    • 程序中的代码(包括在 main 函数中的代码)可以在任何时候访问和修改全局变量和静态变量,只要它们的作用域允许。
  6. 程序结束:

    • 当程序结束时(例如,通过在 main 函数中返回或调用 exit 函数),程序会释放它使用的资源,包括局部变量所占用的栈内存。全局变量和静态变量的生命周期也会随着程序的结束而结束。

总结来说,“在 main 之外的变量”(即全局变量和静态变量)在程序的整个执行期间都是可见的,它们在程序启动时初始化,并可以在程序的任何部分被访问和修改,直到程序结束。局部变量则只在它们所在函数的作用域内存在和可见。


(1)基本整数类型

数据类型描述32位系统大小64位系统大小取值范围
bool布尔类型11true 或 false
char字符型11-128 到 127
signed char有符号字符型11-128 到 127
unsigned char无符号字符型110 到 255
int整型44-2,147,483,648 到 2,147,483,647
unsigned int无符号整型440 到 4,294,967,295
short (或 short int)短整型22-32,768 到 32,767
unsigned short无符号短整型220 到 65,535
long (或 long int)长整型48-2,147,483,648 到 2,147,483,647(32位系统)
-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807(64位系统)
unsigned long无符号长整型480 到 4,294,967,295(32位系统)
0 到 18,446,744,073,709,551,615(64位系统)
long long (或 long long int)长长整型88-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long long无符号长长整型880 到 18,446,744,073,709,551,615

(2)宽字符和多字节字符类型

数据类型描述32位系统大小64位系统大小取值范围
wchar_t宽字符类型2或42或4取决于实现,通常为 0 到 65535 或 0 到 4,294,967,295
char16_tUTF-16 字符类型 (C++11)220 到 65535
char32_tUTF-32 字符类型 (C++11)440 到 4,294,967,295

(3)浮点数类型

为了添加一列表示数据类型的取值范围,更新后的表格如下:

数据类型描述32位系统大小64位系统大小备注取值范围
float单精度浮点数44IEEE 754 标准的单精度浮点数约 -3.4E+38 至 +3.4E+38
double双精度浮点数88IEEE 754 标准的双精度浮点数约 -1.7E+308 至 +1.7E+308
long double长双精度浮点数10, 12 或 1610, 12 或 16大小可能依赖于编译器和平台约 -1.2E+4932 至 +1.2E+4932 (依赖于实现)

(4)标准定义的整数类型(C99/C++11)

数据类型描述典型大小取值范围
int8_t8位有符号整数1-128 到 127
uint8_t8位无符号整数10 到 255
int16_t16位有符号整数2-32,768 到 32,767
uint16_t16位无符号整数20 到 65,535
int32_t32位有符号整数4-2,147,483,648 到 2,147,483,647
uint32_t32位无符号整数40 到 4,294,967,295
int64_t64位有符号整数8-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
uint64_t64位无符号整数80 到 18,446,744,073,709,551,615
intmax_t最大整型8(通常)取决于实现,通常是 int64_t 的范围
uintmax_t最大无符号整型8(通常)取决于实现,通常是 uint64_t 的范围

(5)其他标准类型

你可以通过添加一列来描述这些数据类型的取值范围。下面是更新后的表格:

数据类型描述32位系统大小64位系统大小取值范围
size_t无符号整数,用于大小和长度,至少为 unsigned int 的大小480 到 2^32-1(32位)或 2^64-1(64位)
ptrdiff_t有符号整数,用于指针差,至少为 int 的大小48-2^31 到 2^31-1(32位)或 -2^63 到 2^63-1(64位)
intptr_t用于存储指针的大端或小端字节序的有符号整数48-2^31 到 2^31-1(32位)或 -2^63 到 2^63-1(64位)
uintptr_t用于存储指针的无符号整数480 到 2^32-1(32位)或 2^64-1(64位)
void无值或无类型---

这样,表格不仅说明了每种类型的描述、大小,还补充了它们的取值范围。

(6)复合类型

  • 指针类型:指针类型的大小在32位系统上通常是4字节,在64位系统上通常是8字节。
  • 数组类型:数组的大小是数组中所有元素大小的总和。

(7)枚举类型(enum)

  • 枚举类型的大小取决于实际的值和编译器的实现,但通常是最小的足以包含所有枚举值的整数类型。

(1)用数组名作函数参数

  • 当数组名作为参数传递给函数时,实际上是传递了数组首元素的地址。
  • 形参数组名在函数内部被视为指针变量,因此可以通过指针运算来访问数组元素。

(2)数组定义&初始化

/* 格式
类型符 数组名[常量 或 常量表达式] // 注意,定义时不能用变量。 起始号从 0 开始,左闭右开。
*/
int a[3 + 5];
int a[3][4]; // 定义3行4列数组,注意与引用区分a[2][3]是最后一个元素。在内存中存储是按照行存储,一行元素存完,再存下一行。扩大到多维数组也是这样。
/*初始化
- 定义数值数组,指定长度并初始化,凡未被初始化的元素会自动初始化为0,若是指针类型,则会被自定初始化为NULLL。
*/
// 1) 全部初始化
int a[5] = {0, 1, 2, 3, 4};
int a[] = {0, 1, 2, 3, 4}; // 全部初始化可不指定数组长度
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; // 分行初始化
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // 或者全部写在一个花括号,按照在内存中的顺序对应赋值。
int a[][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // qu
// 2) 部分初始化,只要初始化了,没被赋值的会自动赋0 或 NULL
int a[5] = {0, 1}; // 后面自动填充0
int a[3][4] = {{1}, {5}, {9}} // 只对每行第1列赋值
int a[3][4] = {{1}, {}, {0, 0, 11}} // 对行的某元素赋值
// 3) 全部初始化为0
int a[5] = {0};

(1)结构体指针

typedef void (*KeyFunction)(WORD, int);

typedef关键字用于为数据类型创建一个新的别名。当你看到typedef,基本上可以认为它是在说“我将给某个数据类型起一个新的名字”。

特性/关键字enum (传统枚举)enum class (枚举类)
类型安全性低,可隐式转换为整数高,不可隐式转换为整数
作用域全局作用域,可能导致命名冲突限定在枚举类内部,使用需要作用域解析
底层类型默认为 int,可指定其他类型默认为 int,但编译器可自行选择类型
声明和使用直接使用枚举值必须通过枚举类名限定枚举值
向前声明可以向前声明不能向前声明,需要完全定义
与类型系统的集成较差,不能作为模板参数较好,可以作为类成员和模板参数
访问控制无访问控制可以指定枚举值的访问控制(public, protected, private)
// 基本枚举声明和使用
// 声明一个枚举类型
enum Color {
RED,
GREEN,
BLUE
};
int main() {
Color c = RED; // 使用枚举类型
if (c == RED) {
std::cout << "The color is red." << std::endl;
}
return 0;
}
// 带初始值的枚举
enum Color {
RED = 1,
GREEN = 2,
BLUE = 4
};
int main() {
Color c = GREEN;
std::cout << "The color code is " << static_cast<int>(c) << std::endl;
return 0;
}
// 前向声明枚举
// 前向声明
enum class Color; // 注意使用 class 限定符
Color favoriteColor = Color::RED; // 错误,Color未定义
// 完整的枚举定义
enum class Color {
RED,
GREEN,
BLUE
};
int main() {
// 现在可以正确使用 favoriteColor
return 0;
}
// 枚举类(强类型枚举)
// 枚举类定义
enum class Color {
RED,
GREEN,
BLUE
};
int main() {
Color c = Color::RED;
// 下面的代码将引发编译错误,因为 Color 是强类型枚举
// if (c == 0) { ... }
// 正确的比较方式
if (c == Color::RED) {
std::cout << "The color is red." << std::endl;
}
return 0;
}
// 枚举作为函数参数
void printColorName(Color color) {
switch (color) {
case Color::RED:
std::cout << "Red" << std::endl;
break;
case Color::GREEN:
std::cout << "Green" << std::endl;
break;
case Color::BLUE:
std::cout << "Blue" << std::endl;
break;
}
}
int main() {
printColorName(Color::GREEN);
return 0;
}
// 枚举作为函数参数枚举和迭代器
enum class Color {
RED,
GREEN,
BLUE
};
void printAllColors() {
for (Color color = Color::RED; color != Color::BLUE; ++color) {
std::cout << static_cast<int>(color) << std::endl;
}
}
int main() {
printAllColors();
return 0;
}
#include <iostream>
enum class Color {
RED,
GREEN,
BLUE
};
#define ENUM_COLOR(XX) \
XX(Color::RED) \
XX(Color::GREEN) \
XX(Color::BLUE)
void processColor(Color color) {
std::cout << "Processing color: " << static_cast<int>(color) << std::endl;
}
int main() {
// 使用宏生成多个函数调用
ENUM_COLOR(processColorWrapper)
return 0;
}
// 包装器宏,生成的代码为每个枚举值调用 processColor 函数
#define processColorWrapper(color) processColor(color);
情景是否使用逗号示例
宏用于生成独立的函数调用或语句否ENUM_COLOR(processColor)
生成:
processColor(Color::RED);
processColor(Color::GREEN);
processColor(Color::BLUE);
宏用于生成带逗号分隔的列表(如枚举、参数列表)是ENUM_COLOR_LIST(Color)
生成:
Color::RED,
Color::GREEN,
Color::BLUE

不使用逗号

#define ENUM_COLOR(XX) \
XX(Color::RED) \
XX(Color::GREEN) \
XX(Color::BLUE)
void processColor(Color color);
int main() {
ENUM_COLOR(processColor) // 生成代码如下:
// processColor(Color::RED);
// processColor(Color::GREEN);
// processColor(Color::BLUE);
return 0;
}

使用逗号

#define ENUM_COLOR_LIST(XX) \
XX(Color::RED), \
XX(Color::GREEN), \
XX(Color::BLUE)
enum class Color {
ENUM_COLOR_LIST(IDENT)
// 生成代码如下:
// Color::RED,
// Color::GREEN,
// Color::BLUE
};
#define IDENT(x) x