+5
的源码:0000 0101
(符号位 0,数值位 5 的二进制)-5
的源码:1000 0101
(符号位 1,数值位 5 的二进制)+0
的源码:0000 0000
-0
的源码:1000 0000
+5 + (-5)
需手动处理符号)。+5
的反码:0000 0101
(同源码)-5
的源码:1000 0101
→ 反码:1111 1010
(数值位取反)+0
的反码:0000 0000
-0
的反码:1111 1111
+5(0000 0101) + (-5的反码1111 1010) = 1111 1111(即-0的反码)
,结果需进一步处理。+5
的补码:0000 0101
(同源码)-5
的源码:1000 0101
→ 反码:1111 1010
→ 补码:1111 1011
+0
和 -0
的补码均为 0000 0000
(例如 -0
的源码 1000 0000
→ 反码 1111 1111
→ 补码 1111 1111 + 1 = 1 0000 0000
,8 位下高位进位舍去,结果为 0000 0000
)。2^n
(n 为位数)的模,例如 8 位补码中,-5
的补码等于 256 - 5 = 251
(即二进制 1111 1011
)。+5(0000 0101) + (-5的补码1111 1011) = 1 0000 0000
(8 位下进位舍去,结果为 0000 0000
,即 0)。编码类型 | 正数表示 | 负数表示 | 零的表示 | 运算特性 |
---|---|---|---|---|
源码 | 符号位 0 + 数值位 | 符号位 1 + 数值位 | +0 和-0 不同 |
无法直接用于加减运算 |
反码 | 同源码 | 符号位 1 + 数值位取反 | +0 和-0 不同 |
可简化运算,但仍有缺陷 |
补码 | 同源码 | 反码 + 1 | 唯一(0000...0 ) |
支持直接加减,计算机首选 |
2^8 = 256
,则 -5 ≡ 251 (mod 256)
,251 即 -5
的补码。[-2^(n-1), 2^(n-1)-1]
,例如 8 位补码可表示 -128
到 +127
(其中 -128
的补码为 1000 0000
,无对应的源码和反码)。
continue
(核心场景)for
、while
)中,用于跳过当前循环的剩余代码,直接进入下一次循环迭代。break
)。# 输出1-10中除5以外的数字
for i in range(1, 11):
if i == 5:
continue # 跳过i=5的情况
print(i) # 输出:1,2,3,4,6,7,8,9,10
break
(核心场景)for
/while
)或分支结构(如switch
)中,强制终止当前结构的执行,跳出至外层代码。continue
仅跳过当前迭代)。2. 代码示例(Python)
# 找到第一个能被3整除的数并终止循环
numbers = [1, 2, 4, 5, 7, 9]
for num in numbers:
if num % 3 == 0:
print(f"找到第一个能被3整除的数:{num}")
break # 终止循环
# 输出:找到第一个能被3整除的数:9
break
仅跳出当前层(如需跳出多层,需配合标志位或函数封装)。continue
的对比(编程场景)关键词 | 作用 | 对循环的影响 |
---|---|---|
break |
终止整个循环 / 结构 | 跳出至外层代码,不再执行 |
continue |
跳过当前迭代,继续下一次 | 循环未终止,继续后续迭代 |
return
(核心场景)结束当前循环,退出函数,用在函数体中,返回特定值。
Volatile
(核心场景) volatile
?int a = 0; while(a==0) { ... }
中,若a
未被标记volatile
,编译器可能假设a
值不变,直接优化为死循环)。volatile int flag = 0; // 标记为易变变量
// 线程1: 等待flag被修改
while (flag == 0) {
// 若flag未被标记volatile,编译器可能优化为死循环
}
printf("Flag changed!");
// 线程2: 其他线程修改flag
flag = 1;
volatile
volatile
。volatile unsigned int *GPIO_PIN = (unsigned int*)0x12345678;
volatile
,编译器可能缓存寄存器值,导致硬件操作失效)。volatile
相关的并发问题:
volatile
的局限性:i++
仍需加锁)。关键字 | 解决的问题 | 性能开销 |
---|---|---|
volatile |
可见性、有序性 | 低 |
synchronized (Java) |
原子性、可见性、有序性 | 高 |
lock (C#) |
原子性、资源互斥 | 高 |
public
(仅支持公开访问)。public
/private
/protected
(默认public
,但支持封装)。struct
关键字(除非用typedef
)。struct Point { int x, y; };
struct Point p; // 必须带struct
C++:可直接使用类型名。
struct Point { int x, y; }; Point p; // 无需struct
struct Point p = {1, 2}; // 正确
struct Point p = {.y=2, .x=1}; // C99指定初始化器
C++:
struct Point { int x=0, y=0; };
Point p{1, 2}; // 列表初始化
Point p = {.y=2}; // C++20指定初始化器
#pragma pack
)的较小值对齐。2. 计算示例
// 示例1
struct S1 {
char a; // 1字节 → 偏移0
int b; // 4字节 → 对齐到4的倍数,偏移4(填充3字节)
short c; // 2字节 → 偏移8
}; // 总大小:10 → 对齐到4的倍数,最终12字节
// 示例2(调整顺序)
struct S2 {
int b; // 4字节 → 偏移0
short c; // 2字节 → 偏移4
char a; // 1字节 → 偏移6
}; // 总大小:7 → 对齐到4的倍数,最终8字节
#pragma pack
(C/C++):#pragma pack(1) // 按1字节对齐(取消填充)
struct S3 {
char a; // 1字节 → 偏移0
int b; // 4字节 → 偏移1
short c; // 2字节 → 偏移5
}; // 总大小:7字节
#pragma pack()
int → short → char
),减少填充。#pragma pack
:虽减少空间,但可能降低内存访问效率(非对齐访问更耗时)。struct Empty {}; // sizeof(Empty) = 1
虚函数与虚表:含虚函数的结构体有虚表指针(通常 4/8 字节)。
struct Base { virtual void f() {} }; // sizeof(Base) = 8(64位系统)
特性 | C 语言结构体 | C++ 结构体 |
---|---|---|
默认访问权限 | 全部public |
可指定public /private |
成员函数 | 不支持 | 支持(包括构造 / 析构函数) |
继承与多态 | 不支持 | 支持 |
类型声明 | 需显式写struct |
可直接使用类型名 |
初始化方式 | 聚合初始化 | 支持构造函数、列表初始化 |
空结构体大小 | 未定义(通常 0) | 至少 1 字节 |
内存对齐原则 | 依赖编译器 | 依赖编译器(更复杂) |
class
与struct
的核心区别在 C++ 中,class
和struct
都用于定义自定义数据类型,但它们在默认访问控制、继承方式和设计意图上存在关键差异:
特性 | struct |
class |
---|---|---|
默认成员权限 | public (所有成员公开) |
private (所有成员私有) |
默认继承权限 | public (基类成员保持原权限) |
private (基类成员变为私有) |
struct S {
int a; // 默认public
private:
int b; // 显式设为private
};
class C {
int a; // 默认private
public:
int b; // 显式设为public
};
继承方式:
struct Base { int x; };
struct Derived_S : Base {}; // 默认public继承
class Derived_C : Base {}; // 默认private继承
Derived_S
可访问Base
的public
成员(因public
继承)。Derived_C
无法访问Base
的public
成员(因private
继承)。多态性:
两者均可通过虚函数实现多态,但需注意:
struct Base { virtual void f() {} };
class Derived : public Base { void f() override {} };
Base* ptr = new Derived(); // 需显式public继承才能正确转型
场景 | 推荐使用struct |
推荐使用class |
---|---|---|
数据聚合 | 仅包含数据,无复杂行为 | - |
封装与抽象 | - | 需隐藏实现细节,提供接口 |
面向对象设计 | - | 需继承、多态、复杂方法 |
与 C 兼容 | 纯数据结构(无 C++ 特性) | - |
典型案例:
struct
常用于表示简单数据(如坐标点、配置参数):struct Point { double x, y; }; // 纯数据,无方法
class
常用于实现抽象数据类型(如容器、算法):
class Vector {
private:
int* data;
size_t size;
public:
Vector(size_t n); // 构造函数
~Vector(); // 析构函数
void push_back(int value);
};
struct
:当类型主要是数据集合,且成员需默认公开时。class
:当类型需封装(隐藏实现)、继承或复杂行为时。本质上,C++ 的struct
是 C 结构体的扩展,而class
是 C++ 面向对象特性的核心。选择两者的关键在于访问控制需求和设计意图,而非功能限制(技术上struct
也能实现class
的全部功能)。