https://blog.csdn.net/weixin_48896613/article/details/127371045(内存对齐)
简介:C语言命名规范,内存管理与错误处理,C语言数据类型与内存布局,C语言数据类型转换与精度丢失。
微软命名规范
微软(Microsoft)有严格的编程命名规范,以确保代码的可读性和一致性。以下是一些主要的命名规范和最佳实践:
一般原则
可读性:命名应简洁明了,便于理解。
一致性:保持命名风格的一致性,遵循团队和项目的规范。
描述性:命名应描述变量、函数、类等的用途或功能。
类、接口和结构(都使用驼峰体)
类名:使用 PascalCase(首字母大写的驼峰式),例如
CustomerOrder
。接口名:使用 PascalCase,并以
I
开头,例如ICustomerRepository
。结构名:与类名相同,使用 PascalCase,例如
CustomerRecord
。
方法和属性
方法名:使用 PascalCase,方法名应为动词或动词短语,例如
CalculateTotal
。属性名:使用 PascalCase,属性名应为名词或名词短语,例如
OrderDate
。
变量和字段
局部变量:使用 camelCase(首字母小写的驼峰式),例如
orderTotal
。私有字段:使用 camelCase,并以下划线
_
开头,例如_customerName
。
常量
常量名:使用 PascalCase,例如
MaxOrderQuantity
。对于常量,所有字母都大写并使用下划线分隔单词,例如MAX_ORDER_QUANTITY
。
参数
参数名:使用 camelCase,参数名应为描述性名词,例如
customerName
。
其他
缩写和首字母缩略词:当缩写在标识符中时,使用 PascalCase 或 camelCase 处理,例如
XmlParser
或parseXml
。
变量

//全局变量前面加g_
示例代码
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
public interface ICustomerRepository
{
Customer GetCustomerById(int customerId);
void AddCustomer(Customer customer);
}
public class CustomerOrder
{
private string _customerName;
private DateTime _orderDate;
public string CustomerName
{
get { return _customerName; }
set { _customerName = value; }
}
public DateTime OrderDate
{
get { return _orderDate; }
set { _orderDate = value; }
}
public void CalculateTotal()
{
// Implementation here
}
}
参考资料
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
int main(){
char szBuf[20] = {0};
scanf("%19[0-9]s", szBuf);//0到9
scanf("%19[0, 9, a]s", szBuf);//只有0 9 a
scanf("%19[^8]s", szBuf);//排除8
//scanf的正则
system("pause");
return 0;
}
编译器分配局部变量
编译器在分配局部变量时,通常会依据一些规则和优化策略。以下是一些常见的规则和因素:
栈帧布局: 局部变量通常存储在栈上。每个函数调用都会在栈上创建一个栈帧,栈帧包括局部变量、返回地址和一些其他状态信息。栈帧的大小和布局由编译器决定,通常会根据变量声明的顺序进行分配。
变量声明顺序: 通常情况下,编译器会按照变量在代码中声明的顺序分配内存。即先声明的变量会被分配到较低的内存地址,而后声明的变量会被分配到较高的内存地址(在栈向下增长的系统中)。
对齐要求: 编译器会考虑变量的对齐要求。某些类型的数据(如
int
、double
等)需要在特定的内存地址对齐。编译器会插入适当的填充字节(padding)来满足这些对齐要求。优化策略: 编译器在优化代码时可能会改变变量的分配顺序和位置。例如,它可能会将不常使用的变量分配到离栈指针更远的位置,或将常用的变量保存在寄存器中,而不是在栈上。
函数调用约定: 不同的系统和编译器可能有不同的函数调用约定,这些约定会影响栈帧的布局。例如,有些约定要求保存调用者的寄存器,有些约定则要求保存被调用者的寄存器。
局部变量的生命周期: 编译器会考虑局部变量的生命周期,尽量重用栈空间。比如,一个变量在一个作用域内有效,当离开该作用域时,其占用的栈空间可能会被后续的变量使用。
示例代码
让我们通过一个示例代码来展示局部变量的内存分配:
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
void func() {
int a = 1;
int b = 2;
int c = 3;
printf("Address of a: %p\n", (void*)&a);
printf("Address of b: %p\n", (void*)&b);
printf("Address of c: %p\n", (void*)&c);
}
int main() {
func();
return 0;
}
编译并运行这段代码,你可能会看到如下输出(地址因系统和编译器不同而不同):
- 01
- 02
- 03
Address of a: 0x7ffd5fbff71c
Address of b: 0x7ffd5fbff718
Address of c: 0x7ffd5fbff714
在这个例子中,变量 a
、b
、c
的地址是相邻的,且按照声明的顺序依次递减(假设栈向下增长)。这说明编译器按照变量声明的顺序分配了内存。
内存对齐
https://blog.csdn.net/weixin_48896613/article/details/127371045
一、为什么要内存对齐
内存对齐是为了提高计算机读取数据的效率。对齐地址通常是2、4、8的倍数。
简单来说,就是方便计算机去读写数据。
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
对齐的地址一般都是 n(n = 2、4、8)的倍数。
(1). 1 个字节的变量,例如 char 类型的变量,放在任意地址的位置上;
(2). 2 个字节的变量,例如 short 类型的变量,放在 2 的整数倍的地址上;
(3). 4 个字节的变量,例如 float、int 类型的变量,放在 4 的整数倍地址上;
(4). 8 个字节的变量,例如 long long、double 类型的变量,放在 8 的整数倍地址上;
二、基本变量类型所占大小
不同系统下基本变量类型占用字节数不同,如char为1字节,int为4字节,指针在32位系统下为4字节,在64位系统下为8字节等。

三、影响内存对齐的情况
1、变量排列顺序。
2、attribute((packed)):取消变量对齐,按照实际占用字节数对齐(就是让变量之间排列紧密,不留缝隙)。(gcc才支持)
3、#pragma pack (n):让变量强制按照 n 的倍数进行对齐,并会影响到结构体结尾地址的补齐(详见四的通常情况下关于结尾地址补齐的描述)。
四、重要结论
系统默认对齐规则总结:
结构体中间:各结构体的起始地址按类型变量默认规则排列,char 类型除外,通常按 2 的倍数对齐。
结构体最后:根据最大变量类型对齐。例如,int 需按 4 的倍数对齐,double 需按 8 的倍数对齐。
结构体嵌套:子结构体的成员变量起始地址按子结构体中最大变量类型对齐。
数组成员:按一个字节对齐。
联合体成员:按联合体中最大类型的整数倍对齐。
评论