当前位置: 首页 > article >正文

【C++】Basic Data Types and Operators

在这里插入图片描述

图片由 AI 生成

《C++程序设计基础教程》——刘厚泉,李政伟,二零一三年九月版,学习笔记


文章目录

  • 1、基本数据类型(Fundamental Types)
    • 1.1、数据类型的作用
    • 1.2、常用的 C++ 数据类型
  • 2、常量
    • 2.1、常量的特点
    • 2.2、数值常量的表示
    • 2.3、字符常量
  • 3、变量
    • 3.1、变量的定义
    • 3.2、标识符的命名规则
    • 3.3、变量的初始化与赋值
  • 4、赋值与算术运算符
    • 4.1、赋值运算符与赋值运算表达式
    • 4.2、算数运算符
    • 4.3、自增与自减运算符
  • 5、逻辑运算符和关系运算符
    • 5.1、逻辑常量与逻辑变量
    • 5.2、逻辑运算符和逻辑表达式
    • 5.3、关系运算符和关系表达式
  • 6、其它运算符
    • 6.1、逗号运算符
    • 6.2、复合赋值运算符
    • 6.3、sizeof() 运算符
  • 7、运算符的优先级与结合性
  • 8、数据类型的转换

1、基本数据类型(Fundamental Types)

1.1、数据类型的作用

数据类型规定了数据在计算机内存中存放的格式以及对这些数据所能施加的操作,这样可以有效地提高数据管理的准确性,减少数据操作中错误的发生

1.2、常用的 C++ 数据类型

整数类型(Integer Types)

  • int:标准整数类型,通常为 32 位。
  • short:短整数类型,通常为 16 位。
  • long:长整数类型,通常为 32 位或 64 位(依赖于平台和编译器)。
  • long long:更长的整数类型,通常为 64 位。
  • unsigned int、unsigned short、unsigned long、unsigned long long:无符号版本,不允许负数。

浮点类型(Floating-point Types)

  • float:单精度浮点类型,通常为 32 位。
  • double:双精度浮点类型,通常为 64 位。
  • long double:扩展精度浮点类型,通常为 80 位、96 位或 128 位(依赖于平台和编译器)。

字符类型(Character Types)

  • char:字符类型,通常为8位。
  • signed char:有符号字符类型。
  • unsigned char:无符号字符类型。
  • wchar_t:宽字符类型,用于支持宽字符集(如Unicode)。
  • char16_t:16位字符类型。
  • char32_t:32位字符类型。

布尔类型(Boolean Type)

  • bool:布尔类型,取值为true或false。

数据类型

指针类型(Pointer Types)

  • int*:指向int类型的指针。
  • double*:指向double类型的指针。
  • char*:指向char类型的指针,常用于字符串。

引用类型(Reference Types)

  • int&:int类型的引用。
  • const int&:对int类型的常量引用。

用户定义类型(User-defined Types)

  • 类(Class Types)
  • 结构体(Struct Types)
  • 联合(Union Types)联合允许在相同的内存位置存储不同的数据类型。
  • 枚举(Enumeration Types)

类型修饰符(Type Modifiers)

  • signed:有符号类型(默认情况)
  • unsigned:无符号类型。
  • short:短类型。
  • long:长类型。
  • const:常量类型,变量值不可更改。
  • volatile:告诉编译器该变量可能会被程序之外的因素改变。

类型别名(Type Aliases)

  • C++11引入了 using 关键字来定义类型别名

自动类型推导(Auto Type Deduction)

  • C++11引入了 auto 关键字,让编译器自动推导变量的类型

decltype 类型推导

  • C++11还引入了 decltype 关键字,用于查询表达式的类型

Q:结构体和联合数据类型之间有什么区别和联系?

区别:
在这里插入图片描述

联系

在这里插入图片描述

long double > double > float > long > int > short > char

2、常量

2.1、常量的特点

定义与表示

  • 固定值:常量是程序中的固定值,在程序执行期间不会发生改变。这些固定的值也被称为字面量。
  • 数据类型:常量可以是任何基本数据类型,包括整型数字、浮点数字、字符、字符串和布尔值。
  • 定义方式:
    • 使用 #define 预处理器指令定义符号常量。
    • 使用 const 关键字定义常量变量(即具有常量属性的变量)。
    • 使用 enum 关键字定义枚举常量,枚举常量是一组具有命名值的符号常量。

特性与用途

  • 不可修改性:一旦常量被定义并初始化,其值就不能在程序中被修改。这有助于提高程序的安全性和稳定性。
  • 作用域:常量的作用域与普通变量的作用域相同,可以根据需要定义在全局、命名空间、类或函数内部。
  • 类型安全性:使用const关键字定义的常量具有类型安全性,编译器会在编译阶段进行类型检查。而使用#define定义的符号常量则没有类型区别,只是简单的文本替换。
  • 内存分配:const常量在程序运行时会进行内存分配,并存储在数据段中。而 #define 定义的符号常量则不会分配内存,只是在预处理阶段进行文本替换。
  • 提高代码可读性:使用具有描述性的常量名代替直接出现的数值或字符,可以使代码更加清晰易懂,便于维护和调试。

使用注意事项

  • 初始化:const常量在定义时必须初始化,否则会导致编译错误。而#define定义的符号常量则不需要初始化,因为它只是文本替换。
  • 常量表达式:只有用常量表达式初始化的常量,才能成为常量表达式。常量表达式在编译时就能确定其值,因此可以用于数组大小、枚举值、constexpr变量等需要编译时常量的场景。
  • 指针与常量:指向常量的指针和常量指针在C++中有不同的含义和使用场景。指向常量的指针不能用于修改其所指向的常量值;而常量指针则是指针本身的值(即存储的地址)不能被修改,但其所指向的值可以被修改(除非该值也是常量)。

2.2、数值常量的表示

整形常量

  • 十进制:默认情况下,整数常量是十进制的。例如,123。
  • 八进制:以0(零)开头表示八进制数。例如,015表示八进制数,等于十进制的13。
  • 十六进制:以0x(零叉)或0X开头表示十六进制数。例如,0x1A表示十六进制数,等于十进制的26。
  • 二进制(C++11及以后):以0b(零b)或0B开头表示二进制数。例如,0b1010表示二进制数,等于十进制的10。
  • 长整型:在整数常量后加L或l表示长整型(long)。例如,123L。对于long long类型,使用LL或ll后缀。例如,123456789012345LL。
  • 无符号整型:在整数常量后加U或u表示无符号整型(unsigned)。例如,42u。对于无符号长整型,可以组合使用UL、Lu、uL、llU 等后缀。

浮点数常量 / 实数常量

  • 十进制表示:例如,3.14、0.001。
  • 科学计数法:使用 e 或 E 表示10的幂。例如,1.23e4 表示 1.23 * 10^4,即 12300.0。
  • 浮点数类型后缀:f 或 F 后缀表示 float 类型,l 或 L 后缀表示 long double 类型(如果没有后缀,默认为 double 类型)。例如,3.14f 是 float类型,3.14L 是 long double 类型。

3. 表示 3.0.123 表示 0.123 整数部分和小数部分不能同时省略

2.3、字符常量

字符和字符串常量

  • 字符常量:用单引号括起来的单个字符。例如,‘A’、‘\n’(换行符)。占一个字节
  • 字符串常量:用双引号括起来的字符序列。例如,“Hello, World!”。字符串常量实际上是一个字符数组,以空字符’\0’结尾。
  • 宽字符和宽字符串常量:用L前缀表示宽字符(wchar_t类型)和宽字符串(wchar_t数组)。例如,L’A’、L"Hello"。
  • 原始字符串字面量(C++11及以后):用 R 前缀和双引号括起来,可以包含转义序列而不进行转义。例如,R"(Hello, \"World!\")"表示字符串"Hello, \"World!\""(注意,这里的双引号是字符串内容的一部分,而不是结束符)。不过,原始字符串字面量通常用于包含文件路径等不需要转义的场景。
  • 多行字符串字面量(C++11及以后):虽然C++标准没有直接提供多行字符串字面量的语法,但可以使用原始字符串字面量结合适当的格式来实现多行字符串(尽管每行末尾仍然需要一个双引号和一个括号)。或者,可以使用字符串连接(+运算符或相邻字符串字面量的拼接)来创建多行字符串。
  • 用户定义的文字后缀(C++11及以后):允许为整数、浮点数、字符和字符串字面量定义自定义的后缀,以支持新的字面量类型或进行类型转换。这通常通过模板元编程和constexpr函数来实现。例如,可以定义一个后缀来表示以米为单位的浮点数常量。

转义字符

  • \n:换行符。将光标移动到下一行的开头。ASCII 100
  • \t:水平制表符(Tab)。将光标移动到下一个制表位。
  • \v:垂直制表符。在某些文本编辑器中,它可能表示垂直方向的空格或换行。
  • \b:退格符。将光标向左移动一个字符位置(在某些情况下可能不起作用)。
  • \r:回车符。将光标移动到当前行的开头(在某些情况下,它可能与\n结合使用以表示新行)。
  • \f:换页符。将光标移动到下一页的开头(在大多数现代文本编辑器中,这通常不会改变显示)。
  • \\:反斜杠字符本身。由于反斜杠用于引入转义字符,因此需要使用两个反斜杠来表示一个实际的反斜杠。
  • \':单引号字符。用于在字符常量中表示单引号。
  • \":双引号字符。用于在字符串常量中表示双引号。
  • \?:问号字符。在大多数情况下,问号不需要转义,但在某些特定的上下文中(如正则表达式或字符串字面量中的某些模式匹配),可能需要使用?来避免歧义。
  • \a:警报(蜂鸣)符。在某些系统上,它会使计算机发出蜂鸣声。
  • \x 后跟一个或多个十六进制数字:表示一个十六进制值的字符。例如,\x41 表示字符 ‘A’。
  • \0 或 \000:空字符(null character)。它用于表示字符串的结束。
  • \ddd:其中 ddd 是一个或多个八进制数字(最多三个),表示一个八进制值的字符。例如,\101 表示字符 ‘A’。
  • \xhh:1~2位十六进制数所表示的字符0

转义字符只表示一个字符,在内存中只占一个字节

\n 也可以表示成 \012 或者 \x0a

我们也可以把字符常量看成是整型量,或者说每个字符常量都对应一个整型数值,即它的 ASCII 编码值


看看下面的例子
在这里插入图片描述

3、变量

3.1、变量的定义

变量类型、变量名称、变量值和变量地址

[存储类型] type variable_name [= initial_value];
  • 存储类型即为 autoregiesterstaticextern 之一,缺省时,编译器将根据对该变量的作用域,为该变量指定相应的存储类型
  • type:这是变量的数据类型,它决定了变量可以存储什么类型的数据。例如,int 表示整数,float 表示浮点数,char 表示字符,等等。
  • variable_name:这是变量的名称,它是一个标识符,用于在代码中引用该变量。变量名必须遵循C++的标识符命名规则,通常以小写字母或下划线开头,后跟字母、数字或下划线。
  • [= initial_value]:这是可选的初始值部分。如果提供了初始值,则变量在定义时会被初始化为该值。如果未提供初始值,则变量的初始内容是未定义的(对于基本类型)或依赖于类的默认构造函数(对于对象类型)。

eg

int a;
char c;
float b=3.0;

定义局部变量时不赋初始值,则变量初值不确定

定义全局变量时不赋初始值,则变量初始值为 0

3.2、标识符的命名规则

变量名、函数名、数据名等都是标识符

标识符可由字母、数字、下划线 3 种字符组成

必须以字母或者下划线开头,后面接若干个字母、下划线或数字

变量名不能与 C++ 关键字相同

C++ 的关键字
在这里插入图片描述

auto	自动类型推断
bool	布尔类型
break	跳出当前循环或switch语句
case	switch语句中的一个案例分支
catch	捕获异常块
char	字符类型
char16_t	16位Unicode字符
char32_t	32位Unicode字符
class	定义一个类
const	定义常量或常量表达式
constexpr	定义编译时计算的常量表达式
const_cast	移除对象的常量性
continue	跳过当前循环的剩余部分,直接进行下一次循环
decltype	查询表达式类型
default	switch语句的默认分支或定义默认构造函数
delete	删除分配的内存或禁用特殊成员函数
do	do-while循环的开始
double	双精度浮点数类型
dynamic_cast	安全地转换指针或引用的类型
else	if语句的替代条件分支
enum	定义枚举类型
extern	声明一个变量或函数是在其他地方定义的
explicit	阻止构造函数的隐式自动类型转换
false	布尔字面量false
float	单精度浮点数类型
for	循环控制语句
friend	允许其他类或函数访问私有和保护成员
goto	无条件跳转语句
if	条件语句
inline	建议编译器内联函数
int	整数类型
long	长整型数据类型
mutable	允许const对象的成员被修改
namespace	定义一个命名空间
new	动态内存分配
noexcept	指示函数不抛出异常
nullptr	空指针字面量
operator	定义或重载操作符
private	类的访问修饰符,私有成员
protected	类的访问修饰符,受保护成员
public	类的访问修饰符,公开成员
register	建议编译器将变量存储在寄存器中(已废弃)
reinterpret_cast	重新解释类型的强制类型转换
return	从函数返回值
short	短整型数据类型
signed	有符号类型修饰符
sizeof	计算类型或变量的大小
static	声明静态存储期的变量或类的静态成员
static_assert	编译时断言
static_cast	静态类型转换
struct	定义一个结构体
switch	多路分支选择语句
template	定义模板,用于创建泛型类或函数
this	指向当前对象的指针
thread_local	声明线程局部存储的变量
throw	抛出异常
true	布尔字面量true
try	开始一个异常处理块
typedef	定义类型别名
typeid	在运行时获取类型信息
typename	在模板中声明类型名称
union	定义联合体,多个成员共享同一内存位置
unsigned	无符号类型修饰符
using	引入命名空间的成员或定义类型别名
virtual	声明虚函数或虚基类
void	指定无返回值或作为通用指针类型的基础
volatile	指定变量可能被意外修改,防止编译器优化
wchar_t	宽字符类型
while	循环控制语句

3.3、变量的初始化与赋值

type variable_name = initial_value;
float a=3.0, b=a*2.5;
char c = 'n';

注意事项

  • 必须初始化的情况:对于引用和const变量,必须在声明时进行初始化,因为它们一旦被创建就不能再被改变。
  • 避免未定义行为:对于内置类型,如果未初始化就使用变量,则可能导致未定义行为。因此,最好总是在声明时初始化变量,或者在使用之前确保它们已被正确初始化。
  • 赋值与初始化的区别:虽然赋值和初始化都涉及为变量设置值,但它们在发生时间和语义上有所不同。初始化发生在变量创建时,而赋值发生在变量创建后的某个时刻。

4、赋值与算术运算符

4.1、赋值运算符与赋值运算表达式

#include <iostream>
using namespace std;

int main()
{
    int var1, var2, var3;
    var1 = (var2 = var3 = 10) + 20;
    cout << "var1=" << var1 << endl;
    return 0;
}

output

var1=30

过度使用这种链式赋值或嵌套赋值可能会使代码难以阅读和维护。因此,建议在使用赋值表达式时保持清晰和简洁。

4.2、算数运算符

算数运算符用于操作变量或表达式的算数运算

加法运算符 (+):

  • 该运算符用于计算两个数的和。
  • 例如: 5 + 3 会得出 8。

减法运算符 (-):

  • 用于计算两个数的差。
  • 例如: 5 - 3 的结果是 2。

乘法运算符 (*):

  • 用来计算两个数的乘积。
  • 例如: 5 * 3 等于 15。

除法运算符 (/):

  • 用于计算两个数的商。
  • 例如: 5 / 2 的结果是 2(在C++中,整数除法会舍去小数部分)。
  • 若要获取精确的除法结果(包括小数部分),可以使用浮点类型(如 float 或 double)。

取模运算符 (%):

  • 该运算符返回除法运算的余数。
  • 例如: 5 % 2 的结果是 1。

正号运算符 (+):

  • 用来表示数的正值(实际上,在C++中,正号通常不是必需的,因为数本身就是正的,除非指定为负)。
  • 例如: +5 仍然是 5。

负号运算符 (-):

  • 用于表示数的负值。
  • 例如: -5 表示 -5。
#include <iostream>
using namespace std;

int main()
{
    int a = 5, b = 3;
    std::cout << "a + b = " << a + b << std::endl; // 输出 8
    std::cout << "a - b = " << a - b << std::endl; // 输出 2
    std::cout << "a * b = " << a * b << std::endl; // 输出 15
    std::cout << "a / b = " << a / b << std::endl; // 输出 1(整数除法)
    std::cout << "a % b = " << a % b << std::endl; // 输出 2(余数)
 
    a++; // a 现在等于 6
    std::cout << "a after a++ = " << a << std::endl; // 输出 6
 
    b--; // b 现在等于 2
    std::cout << "b after b-- = " << b << std::endl; // 输出 2
    return 0;
}

outpu

a + b = 8
a - b = 2
a * b = 15
a / b = 1
a % b = 2
a after a++ = 6
b after b-- = 2

除数为 0 和实数溢出被视为严重错误而导致程序运行的异常终止

整数溢出不认为是一个错误(尽管其运算结果有可能与预期值不同)

4.3、自增与自减运算符

有前置和后置两种

后置对操作数先引用再进行自增或自减,前置相反

自增运算符 (++):

  • 用于将变量的值增加1。
  • 可以作为前缀(如 ++a)或后缀(如 a++)使用,但在表达式中的行为有所不同。

自减运算符 (–):

  • 用于将变量的值减少1。
  • 同样,它可以作为前缀(如 --a)或后缀(如 a–)使用。
#include <iostream>
using namespace std;

int main()
{
    int i=1,j,k;
    j = ++i;
    k = i++;
    cout << "i=" << i << endl;
    cout << "j=" << j << endl;
    cout << "k=" << k <<endl;
    return 0;
}

output

i=3
j=2
k=2

5、逻辑运算符和关系运算符

5.1、逻辑常量与逻辑变量

虽然 C++ 设立了逻辑类型,但是编译系统处理逻辑型数据时,仍将 false 处理为 0,将 true 处理为 1。

#include <iostream>
using namespace std;

int main()
{
    bool found, flag=false;
    found = true;
    cout << found << " " << flag << endl;
    flag = 108;
    cout << found << " " << flag << endl;
    return 0;
}

output

1 0
1 1

5.2、逻辑运算符和逻辑表达式

逻辑与(AND)运算符:&&

  • 功能:当两个操作数都为true时,结果为true;否则为false。
  • 示例:如果bool a = true; bool b = false; 则bool result = a && b; 的结果为false,因为b为false。
  • 优先级:逻辑与的优先级高于逻辑或,但低于逻辑非和关系运算符。

逻辑或(OR)运算符:||

  • 功能:当两个操作数中至少有一个为true时,结果为true;如果两个都是false,结果为false。
  • 示例:如果bool a = true; bool b = false; 则bool result = a || b; 的结果为true,因为a为true。
  • 优先级:逻辑或的优先级是逻辑运算符中最低的。

逻辑非(NOT)运算符:!

  • 功能:将操作数的布尔值取反。如果操作数为true,结果为false;如果操作数为false,结果为true。
  • 示例:如果bool a = true; 则bool result = !a; 的结果为false,因为a是true。
  • 优先级:逻辑非的优先级最高,高于逻辑与和逻辑或。
#include <iostream>
using namespace std;

int main()
{
    bool a = true, b = false, c = true;
    
    std::cout << "a && b: " << (a && b) << std::endl; // 输出 0(false)
    std::cout << "a || b: " << (a || b) << std::endl; // 输出 1(true)
    std::cout << "!a: " << !a << std::endl;          // 输出 0(false)
    std::cout << "a && c || !b: " << (a && c || !b) << std::endl; // 输出 1(true),因为a && c为true
    
    return 0;
}

output

a && b: 0
a || b: 1
!a: 0
a && c || !b: 1

5.3、关系运算符和关系表达式

等于运算符(==)

  • 功能:判断两个值是否相等。
  • 示例:如果int a = 5, b = 5; 则bool result = (a == b); 的结果为true,因为a和b相等。

不等于运算符(!=)

  • 功能:判断两个值是否不相等。
  • 示例:如果int a = 5, b = 10; 则bool result = (a != b); 的结果为true,因为a和b不相等。

大于运算符(>)

  • 功能:判断左边的值是否大于右边的值。
  • 示例:如果int a = 10, b = 5; 则bool result = (a > b); 的结果为true,因为a大于b。

小于运算符(<)

  • 功能:判断左边的值是否小于右边的值。
  • 示例:如果int a = 5, b = 10; 则bool result = (a < b); 的结果为true,因为a小于b。

大于等于运算符(>=)

  • 功能:判断左边的值是否大于或等于右边的值。
  • 示例:如果int a = 10, b = 10; 则bool result = (a >= b); 的结果为true,因为a大于或等于b。

小于等于运算符(<=)

  • 功能:判断左边的值是否小于或等于右边的值。
  • 示例:如果int a = 5, b = 10; 则bool result = (a <= b); 的结果为true,因为a小于或等于b(在这个例子中,实际上是小于)。
#include <iostream>
using namespace std;

int main()
{
    int x = 10, y = 20;
    
    std::cout << (x == y) << std::endl; // 输出 0 (false),因为10不等于20
    std::cout << (x != y) << std::endl; // 输出 1 (true),因为10不等于20
    std::cout << (x > y) << std::endl;  // 输出 0 (false),因为10不大于20
    std::cout << (x < y) << std::endl;  // 输出 1 (true),因为10小于20
    std::cout << (x >= y) << std::endl; // 输出 0 (false),因为10不大于或等于20
    std::cout << (x <= y) << std::endl; // 输出 1 (true),因为10小于或等于20(实际上是小于)

    return 0;
}

output

0
1
0
1
0
1

eg 2-2,计算某年的5月4日是这一年的第几天

#include <iostream>
using namespace std;

int main()
{
    int year;
    cout << "请输入年份:" << endl;
    cin >> year;
    int day = 31 + 28 + 31 + 30 + 4;

    if ((year % 4 == 0 && year % 100 != 0) || ( year% 400 == 0))
        day++;
    cout << year << "年的第" << day << "天是5月4号" << endl;

    return 0;
}

output

请输入年份:
2000
2000年的第125天是54

一个年份如果能被4整除但不能被100整除,或者能被400整除,那么它就是闰年。

6、其它运算符

6.1、逗号运算符

逗号运算符的优先级是最低的,必要时要加上圆括号,以使逗号表达式的运算次序优于其他表达式

6.2、复合赋值运算符

C++还提供了复合赋值运算符,它们结合了算术、位运算或移位运算与赋值运算,产生一个新的双目操作符。这些运算符使代码更简洁、更易读。

+=:加法赋值运算符,例如 a += 3 等价于 a = a + 3-=:减法赋值运算符,例如 a -= 2 等价于 a = a - 2*=:乘法赋值运算符,例如 a *= 4 等价于 a = a * 4/=:除法赋值运算符,例如 a /= 2 等价于 a = a / 2%=:取模赋值运算符,例如 a %= 3 等价于 a = a % 3<<=:左移赋值运算符,例如 a <<= 1 等价于 a = a << 1>>=:右移赋值运算符,例如 a >>= 1 等价于 a = a >> 1&=:按位与赋值运算符,例如 a &= b 等价于 a = a & b。
|=:按位或赋值运算符,例如 a |= b 等价于 a = a | b。
^=:按位异或赋值运算符,例如 a ^= b 等价于 a = a ^ b。

共 10 种

6.3、sizeof() 运算符

sizeof 运算符在C和C++编程语言中用于获取类型或对象在内存中的大小(以字节为单位)。这个运算符在编译时计算其操作数的大小,并返回一个 size_t 类型的值。sizeof 可以应用于数据类型、数组、指针、结构体、联合体等。

sizeof 不是函数,而是一种单目操作符

eg:基本数据类型

#include <iostream>
using namespace std;

int main()
{
    printf("Size of char: %zu bytes\n", sizeof(char));
    printf("Size of int: %zu bytes\n", sizeof(int));
    printf("Size of float: %zu bytes\n", sizeof(float));
    printf("Size of double: %zu bytes\n", sizeof(double));

    return 0;
}

output

Size of char: 1 bytes
Size of int: 4 bytes
Size of float: 4 bytes
Size of double: 8 bytes

eg:数组

#include <iostream>
using namespace std;

int main()
{
    int arr[10];
    printf("Size of array: %zu bytes\n", sizeof(arr));  // Total size of the array
    printf("Size of one element: %zu bytes\n", sizeof(arr[0]));  // Size of one element
    printf("Number of elements in the array: %zu\n", sizeof(arr) / sizeof(arr[0]));  // Number of elements
    
    return 0;
}

output

Size of array: 40 bytes
Size of one element: 4 bytes
Number of elements in the array: 10

eg 结构体

#include <iostream>
using namespace std;

struct MyStruct {
    int a;
    float b;
    char c;
};

int main()
{
    struct MyStruct s;
    printf("Size of struct: %zu bytes\n", sizeof(s));
    printf("Size of a: %zu bytes\n", sizeof(s.a));
    printf("Size of b: %zu bytes\n", sizeof(s.b));
    printf("Size of c: %zu bytes\n", sizeof(s.c));

    return 0;
}

output

Size of struct: 12 bytes
Size of a: 4 bytes
Size of b: 4 bytes
Size of c: 1 bytes

存在对齐操作

eg:指针

#include <iostream>
using namespace std;

int main()
{
    int *ptr;
    printf("Size of pointer: %zu bytes\n", sizeof(ptr));
    
    return 0;
}

ouput

Size of pointer: 8 bytes

sizeof 运算符在编译时计算大小,而不是在运行时

使用 sizeof 运算符时,如果操作数是一个表达式(而不是类型),表达式不会被实际计算,只是计算表达式结果类型的大小。例如,sizeof(5 + 3) 将返回 sizeof(int),3+5 并不会被计算。

#include <iostream>
using namespace std;

int main()
{
    int a =2;
    cout << sizeof(a=3) << endl;
    cout << a << endl;

    return 0;
}

output

4
2

7、运算符的优先级与结合性

在这里插入图片描述
在这里插入图片描述

8、数据类型的转换

不同类型数据进行混合运算时,必须先转化为同一类型,然后再进行运算。

(1)隐式转换

也称自动转换

当一个表达式种出现两种不同的数据类型时,C++ 将级别低的数据类型自动转化成级别高的数据类型,或将占用字节少的类型转化为占用字节数多的类型

在这里插入图片描述

#include <iostream>
using namespace std;

int main()
{
    float a = 'A' - 10 + 5 * 2.0 + 20.8 / 4;
    cout << a;

    return 0;
}

output

70.2

(2)显式转换

也称强制转换

类型 (表达式)
(类型) 表达式

eg

#include <iostream>
using namespace std;

int main()
{
    double b = 5.5;
    int c = 20 / (int) b;
    //int c = 20 / int (b);

    cout << b << endl;
    cout << c << endl;

    return 0;
}

output

5.5
4

注意,这里的 b 值没有变

补充

  • static_cast,用于在具有明确转换关系的类型之间进行转换,如从基类指针转换为派生类指针(在运行时是安全的)、从整数类型转换为枚举类型等。
  • dynamic_cast,主要用于多态类型的向下转换(从基类指针或引用转换为派生类指针或引用),并且只能在包含虚函数的类之间使用。如果转换失败,dynamic_cast将返回nullptr(对于指针)或抛出std::bad_cast异常(对于引用)。
  • const_cast,用于添加或移除const限定符。它不能用于改变变量的类型,只能用于改变const属性。
  • reinterpret_cast,是一种非常底层的转换,它几乎不对转换进行任何检查。它主要用于将指针类型转换为其他指针类型(例如,将void*转换为其他类型的指针),或者将指针转换为整数类型(例如,获取指针的地址)。使用reinterpret_cast是非常危险的,因为它可能导致未定义行为。

http://www.kler.cn/a/551742.html

相关文章:

  • C# 适合做什么项目?全面解析 C# 的应用领域与优势
  • C语言——指针基础知识
  • 六、敏捷开发工具:项目管理工具
  • Ubuntu22.04系统安装使用Docker
  • 【个人总结】7. Linux 工作三年的嵌入式常见知识点梳理及开发技术要点(欢迎指正、补充)
  • 从零开始构建一个小型字符级语言模型的详细教程(基于Transformer架构)之二模型架构设计
  • 高效执行自动化用例:分布式执行工具pytest-xdist实战!
  • 分布式理论与分布式算法
  • TS .d.ts 到底怎么用?
  • 【小白学AI系列】NLP 核心知识点(七)Embedding概念介绍
  • 构建高效 Python Web 应用:框架与服务器的选择及实践
  • 【NLP 25、模型训练方式】
  • Spring Boot实现跨域
  • Unity项目实战-订阅者发布者模式
  • C语言——指针进阶应用
  • 利用分治策略优化快速排序
  • 2013年下半年软件设计师上午题考察知识点及其详细解释(附真题及答案解析)
  • MAVEN学习
  • 使用brew install python,跟 Mac自带的python版本会发生冲突吗?
  • 【数据结构】(10) 排序算法