c语言查漏补缺

  1. 结构体对齐

    1. 编译器对齐 4字节, int以下集中对齐
    2. 鲲鹏优化时候,字节对齐会影响原子操作 coredump
  2. NUMA 优化 (鲲鹏处理器优化)

    socket 里面有多个 core, 鲲鹏2个core算一个NUMA node(逻辑概念), 一个node分配一些资源(4个DDR通道)

    1. 设置网卡中断的cpu亲和性,减少跨 NUMA core产生的额外开销

      echo c p u M a s k > / p r o c / i r q / cpuMask > /proc/irq/ cpuMask>/proc/irq/irq/smp_affinity_list

    2. numactl 可以指定程序运行的内核位置

      numactl -C 28-31 ./test

    3. C/C++代码中通过 sched_setaffinity 函数来设置线程亲和性

    4. 软件设置

  3. CacheLine优化(鲲鹏处理器优化)

    将 频繁写的变量(锁)声明为 CacheLine对齐

  4. 指针篇

    1. 指针有三个属性: 类型名称

    2. 指针操作有 赋值 和 加 指针变量 + 数字 = 指针变量值 + 数字 * sizeof(指向类型)

    3. 数组名 和 指针

      1. 举例子int a[10],*p=a;

      2. 数组名称 a 相当于地址常量, 那么这个地址指向一段内存, 因此这个地址本身会有指向类型, 其指向类型就是数组的元素类型. 例如int a[10], 那么a的 指向类型 就是int, 即 a, p操作等价**.

      3. &a的指针值和a的指针 一样, 而且也是个地址常量,

      4. 数组的sizeof值等于数组所占用的内存字节数,

        sizeof(a)计算整个数组的类型,40
        sizeof(*a)计算a指向类型的大小,即 int,4
        &a的指向类型是 int(*) [10], 即指向一个包含10个int元素的数组指针,行指针, 所以sizeof(&a), 计算&a的指向类型的占用内存大小就是40.
      5. 数组作为函数参数传递后, 在函数内使用等价于指针. 因为函数传参是进行值传递, 相当于有一个指针变量记录数组的地址值.

    4. 函数指针

      1. 对函数名本身计算类型占用内存大小, 其值为1, 对于函数名的指向类型计算内存占用大小其值也为1.

      2. foo, *foo, &foo的类型相同, 但是sizeof(&foo)结果为8.

      3. 函数指针可以进行多次解引用, *****p_foo == *p_foo = p_foo.

      4. 函数指针可以进行调用, p_foo(3);

        以上几点可以认为是函数的特殊情形, 直接记忆.

        可以将函数的指令看作是一个unsigned char []的数组. 这样函数名就好像是一个数组名一样, 都是地址常量, 其指向类型为unsigned char类型. 但是函数指令的数组的长度是未知的, 因此编译器默认输出sizeof(foo)为1, sizeof(*foo)相当于是sizeof(unsigned char)为1.

    5. expample

   #include <stdio.h>
// different between a and &a;
int main (void)
{
	printf("hello\r\n");
	int q[4]={1,2,3};
	int a[4]={1,2,3};// This is where we will began.
	int b[4]={1,2,3};

	printf("%d %d\r\n",a[1],*(a+1));
	
	printf("%d %d\r\n",a,&a);
	
	printf("%d %d\r\n",(a+1),(&a+1));
	
	printf("%d %d %d\r\n",q,*(&a+1),**(&a+1));
}
	

用 TinyC 运行(ArmC6同样运行通过)

$ tcc -run test.c		#变量有3个要素,名字、类型和数值,a和&a
hello
2 2						# a[1],*(a+1) 结果一致,也就是民间传言的,a和&a,指针和数组名一致
6486732 6486732			# 开始验证 a 和 &a,数值相同
6486736 6486748			# 继续验证,运算规则不同,说明类型不同
6486748 6486748 1		# 经过尝试,理解语法,我怀疑&a是一个数组指针 int(*)[4] 类型,指着0号位

我们用二维数组 和 数组指针(行指针)来说明下问题。

   #include <stdio.h>
   // 
   int main (void)
{
	printf("hello\r\n");
	int q[4]={1,2,3};
	int a[4][2]={1,2,3};// This is where we will began.
	int b[4]={1,2,3};

	printf("%d %d %d\r\n",a[1],*(a+1),(*(a+1)+0));

	printf("%d %d %d\r\n",*(*(a+1)+0),*(a[1]+0),a[1][0]);

	printf("%d %d %d\r\n",b,&a+1,(*(&a+1))[1][0]);
	//--------vertify the conjecture now -----
	printf("-----------------------------------------------\r\n");
	
	int (*p)[2]=a+1;//注意*[]的优先级,这里定义了行指针、数组指针。int *p[2] 是指针数组的定义。双重指针 和 指针数组的定义方式 不同于 二维数组。	
	p = a+0;
	printf("%d %d %d\r\n",p[1][0],**(p+1),a[1][0]);
	p = &q;
	printf("%d %d %d\r\n",p[0][1],*(p[0]+1),q[1]);
}

来看一下,分析一下结果

$ tcc -run test.c
hello
6486724 6486724 6486724			#复习常见的二维数组操作
3 3 3
6486700 6486748 3				# 同理,此处&a 不是行指针,而是更高的数组指针int (*)[4][2]
-----------------------------------------------
3 3 3							#&q and a都是行指针类型 int(*)[]
2 2 2							#此处验证一下,一维数组q可以用数组指针来操作,只要保证第零行就行



参考链接

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐