C语言思考题
思考题一
c语言中,什么是字节对齐?如何在代码中实现字节对齐?
在结构体定义中存在字节对齐的问题,这是因为某些早期的CPU架构并不支持奇数地址的访问或者偶数地址访问的速度比奇数地址访问的速度快
所以结构体定义的变量开始位置会对齐到偶数的地址上,而关于结构体中每个变量的偏移地址也会进行“对齐”,C语言中默认时4字节对齐
也可以对其进行修改
1 |
|
每个变量偏移地址必须为min(N, 结构体变量的大小)
的整数倍
C语言结构体字节对齐规则
规则1 :结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存放在offset为该数据成员大小的整数倍的地方(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
规则2:如果一个结构体B里嵌套另一个结构体A,则结构体A应从offset为
min(A内部最大成员, 对齐字节)
的整数倍的地方开始存储。(struct B里存有struct A,A里有char,int,double等成员,那A应该从8的整数倍开始存储。),结构体A中的成员的对齐规则仍满足原则1、原则2。Tips:结构体A所占的大小为该结构体成员内部最大元素的整数倍,不足补齐。而不是直接将结构体A的成员直接移动到结构体B中
规则3:结构体的总大小,也就是sizeof的结果,必须是
min(内部最大成员的整数倍, 对齐字节)
,不足的要补齐。
思考题二
c语言里面指针函数和函数指针的区别,代码中如何使用?
指针函数本质上是一个返回指针的函数,仅仅是一个函数,返回类型为指针类型,例如malloc
函数指针是一个指向函数的指针。它的类型决定了它指向的函数的参数类型和返回类型。函数名本身就可作为函数指针作为其他函数的传入参数,例如 pthread_create 创建线程时就需要一个void () (void *) 的函数指针作为传入参数
思考题三
c语言进程运行过程中,如何使用gdb进行实时调试,获取变量值?如果进程产生core,如何定位core的位置?明确core的具体原因?
想要调试正在运行的进程,首先你要找到想要调试的进程的进程号,确保该进程编译的时候带-g选项,有调试信息
例子
1 |
|
1 |
|
要让C语言程序生成核心转储(core dump)文件,你需要确保系统配置允许生成(ulimit -a)
例子
1 |
|
1 |
|
生成核心转储文件(coredump)通常需要满足以下条件:
- 进程必须有足够的权限:通常,只有进程的拥有者或root用户才能生成核心转储文件。
- 系统内核参数:/proc/sys/kernel/core_pattern 决定了核心转储文件如何命名和存储。默认情况下,生成的核心转储文件可能不会出现在用户目录中。
1 |
|
在一个函数中char *p = “hello”;与char p[] = “hello”;的区别
char *p = “hello”;
这是一个指向字符的指针的声明。
p 是一个指向常量字符串 “hello” 的指针。
“hello” 是一个常量字符串,存储在只读内存区域。
你不能通过 p 来修改 “hello” 中的字符,因为它是只读的。
例如,p[0] = ‘H’; 是非法的,因为这会尝试修改只读内存。char p[] = “hello”;
这是一个字符数组的声明。
p 是一个有 6 个元素的数组,包含字符 ‘h’, ‘e’, ‘l’, ‘l’, ‘o’, 和字符串结束符 ‘\0’。
数组 p 存储在堆栈上,是可读写的。
你可以通过数组索引来修改数组中的字符,例如 p[0] = ‘H’; 是合法的。
int(*Func())[10] 和 int (*a[5])()
int(*Func())[10]; 这行代码声明了一个函数指针Func。这个函数指针指向的函数返回一个指向包含10个整数的数组的指针。具体来说:
int(*)[] 表示返回一个指向数组的指针,这个数组的内容类型是int。
[10] 表示这个数组有10个整数。
所以,Func是一个指向函数的指针,这个函数返回一个整型数组的指针。简而言之,Func是一个函数指针,它指向的函数返回一个整型数组。
int (*a[5])(); 这行代码声明了一个数组a,这个数组有5个元素,每个元素是一个函数指针。具体来说:
a[5] 表示这是一个有5个元素的数组。
* 表示数组的元素是指针。
() 表示这些指针指向的函数。
int 表示这些函数返回一个整数。
因此,a是一个由5个函数指针组成的数组,每个指针指向一个返回整数类型的函数。