以前不知道的小知识

Dummy节点

有时候在做链表操作的时候,可能会出现传入的head或者root被操作后删除的情况,所以为了防止操作后这个指针变成空导致其他板块崩溃,需要声明一个链表结构体Dummy来

dummy.next = head;

这样就可以返回dummy.next,防止出现返回null,链表找不到了。 

并查集

并查集(Disjoint Set Union,简称 DSU)是一种数据结构,用于处理一些不交集的合并及查询问题。

内存对齐

内存对齐是一种内存管理技巧,旨在提高存取效率。它涉及到如何按照特定的边界安排内存地址,以便于硬件访问数据。在许多计算机系统中,硬件(如CPU)更高效地访问某些特定对齐的内存地址,这可能是2的幂次或者数据类型大小的倍数。

举个例子,如果一个整型(int)占用4个字节,那么在许多系统上,这个整型数据最好存放在内存地址是4的倍数的地方。当数据在这样的边界上对齐时,CPU可以一次性、最高效地读取或写入数据。

内存对齐的重要性主要体现在以下几个方面:

1. **性能优化**:对齐的数据可以让硬件一次性读取或写入,而不需要分多次操作,从而提高存取速度。

2. **硬件要求**:有些硬件平台要求数据对齐,不遵守这些规则可能导致硬件异常或程序崩溃。

3. **避免额外的成本**:不对齐的数据访问可能导致额外的处理成本,如需要额外的指令和更多的CPU周期来处理不对齐的数据。

编程时需要考虑内存对齐的情况:

- **编译器对齐**:现代编译器通常会自动处理变量的内存对齐问题。编译器可能提供特定的指令或属性来控制特定数据的对齐方式。

- **结构体对齐**:在定义结构体时,编译器通常会根据最宽的成员对齐整个结构体,并在结构体的成员之间插入填充字节(padding)以保持对齐。

- **平台依赖性**:不同的平台可能有不同的对齐要求,开发者需要了解目标平台的具体要求。

- **手动对齐**:在某些情况下,开发者可能需要手动管理内存对齐,例如在使用自定义内存分配器或进行底层系统编程时。

在编写程序时,通常不需要过多关注内存对齐的问题,因为编译器会帮助我们处理大部分情况。然而,在进行系统编程、优化性能或者移植代码到不同的硬件平台时,内存对齐就变得非常重要。

例子

定义两个结构体,调整成员顺序,最后打印发现my_st1被对其到了12位,my_st2则将b,c两个成员放在了相邻的位置,所以我的环境应该是4位对齐的。

#include <stdio.h>

typedef struct my_st1
{
    char a;
    int b;
    short c;
}my_st1_t;

typedef struct my_st2
{
    int a;
    short b;
    char c;
}my_st2_t;
int main()
{
    my_st1_t structure1;
    printf("___st1___\n");
    printf("size is %ld\n",sizeof(structure1));
    printf("pa = %p, pb = %p, pc = %p\n", &structure1.a, &structure1.b, &structure1.c);
    my_st2_t structure2;
    printf("___st2___\n");
    printf("size is %ld\n",sizeof(structure2));
    printf("pa = %p, pb = %p, pc = %p\n", &structure2.a, &structure2.b, &structure2.c);
}
//运行结果
// ___st1___
// size is 12
// pa = 0x7ffd1d0bc2ac, pb = 0x7ffd1d0bc2b0, pc = 0x7ffd1d0bc2b4
// ___st2___
// size is 8
// pa = 0x7ffd1d0bc2a4, pb = 0x7ffd1d0bc2a8, pc = 0x7ffd1d0bc2aa

符号位扩展

符号位扩展(Sign Extension)是计算机科学中的一个概念,通常涉及在将较小的数据类型转换为较大的数据类型时,如何处理带符号的整数。这个过程确保了带符号数值在扩展后保持其原有的符号和数值。

当对一个带符号的整数进行符号位扩展时,需要将其符号位(最高位)复制到新的更大数据类型的高位部分。例如,假设我们有一个8位的带符号整数(在二进制表示中,最高位是符号位),如果我们想要将这个整数扩展到16位,那么我们需要复制原来的符号位到新的高8位。

这里举一个具体的例子:

假设我们有一个8位的带符号整数 `10101010`,其表示为一个负数(因为最高位是1)。如果我们将这个数扩展为16位,我们需要将符号位(1)复制到新的高8位,因此扩展后的数为 `11111111 10101010`。这样扩展后的数值与原数值在数学上是相等的。

符号位扩展的步骤如下:

1. 确定原始数值的大小和符号位。
2. 创建一个新的、更大的数据类型,其大小足以容纳原始数值。
3. 将原始数值的所有位复制到新数据类型的低位部分。
4. 根据原始数值的符号位,将新数据类型的高位全部设置为0(如果符号位是0,即原始数值为正数)或全部设置为1(如果符号位是1,即原始数值为负数)。

符号位扩展在很多编程场景中都很重要,特别是在进行算术运算、位操作和系统编程时。正确的符号位扩展可以确保数值的正确性,避免可能的错误和异常。

例子

#include <stdio.h>
int main(void)
{
    char a = 0b10101010;
    unsigned char b = 0b10101010;
    int c = ~a;
    int d = ~b;
    printf("a = %08x, b = %08x, c = %08x,d = %08x\n", a, b, c, d);
    printf("pa = %08x, pb = %08x, pc = %08x,pd = %08x\n", &a, &b, &c, &d);
}

// 运行结果
// a = ffffffaa, b = 000000aa, c = 00000055,d = ffffff55
// pa = 803c356e, pb = 803c356f, pc = 803c3570,pd = 803c3574

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值