Linux中的栈

1. 内核栈 在每一个进程的生命周期中,必然会通过到系统调用陷入内核。在执行系统调用陷入内核之后,这些内核代码所使用的栈并不是原先进程用户空间中的栈,而是一个单独内核空间的栈,这个称作进程内核栈。 1.1. init_task init_task,也就是bootcpu的swapper进程对应的task_struct,其内核栈是静态初始化的。 1/// init/init_task.c 2/* 3 * Set up the first task table, touch at your own risk!. Base=0, 4 * limit=0x1fffff (=2MB) 5 */ 6struct task_struct...

栈帧寄存器相关的编译选项

1. 编译选项 -fomit-frame-pointer表示在函数调用时不需要存储堆栈帧指针。此选项可减小生成的代码镜像大小, 一般在启用-On优化后会自动打开,也有的平台是默认打开的。 -fno-omit-frame-pointer表示将堆栈帧指针存储在寄存器中,帧指针是用来指示当前函数的栈帧(stack frame)的指针,在调试时可以帮助跟踪函数调用的堆栈信息。 在 AArch32 架构中,堆栈帧指针存储在寄存器R11A32代码)或寄存器R7T32代码)中. 在AArch64架构中,堆栈帧指针存储在寄存器X29中。作为帧指针使用的寄存器不能用作通用寄存器,但如果使用 -fomit-frame-pointer选项编译,则可用作...

用memcmp比较结构体会有什么问题

1. 示例一 先看下如下代码,思考一下,结果是输出a == b还是a != b? 1#include <stdio.h> 2#include <string.h> 3 4struct test_type { 5 char name[10]; 6 int i; 7 long l; 8}; 9 10int main(void) 11{ 12 struct test_type a = { 13 "test", 1, 2 14 }; 15 struct test_type b; 16 17 b.i = a.i; 18 b.l = a.l; 19 strcpy(b.name, a.name); 20 21 if (0 ==...

C语言编译断言

1. 简介 c++17标准引入了static_assert。 1static_assert(bool-constexpr, message ) /// since C++11 2static_assert(bool-constexpr) /// since C++17 gnu c编译器也实现了_Static_assert,见Static Assertions。 2. 自定义 在没有static_assert的c语言中,可以自己实现类似的功能,如下: 2.1. 方法一 1#ifndef STATIC_ASSERT 2#define STATIC_ASSERT(exp)...

多维数组作为函数参数

1. 方法一:传递数组 C语言对多维数组的存储是按照一维数组来处理的,数组的每个维度在内存中按顺序存储。所以将多维数组作为参数传递时,必须指定多维数组子维度的大小,否则函数无法得知每个子维度结束地址。 第一维的长度可以指定,也可以不指定。 1void func1(int a1[], int x); 2void func2(int a2[][4], int x, int y); 3void func3(int a3[][4][8], int x, int y, int z); 2. 方法二:数组指针 把参数声明为指向数组的指针,此方法还是需要指定数组的子维度大小,不然函数内部无法使用下标去访问数组。 1void func1(int...

数组a、&a、&a[0]、&a[0][0]的区别与联系

1. 测试结果 分别声明一个一维数组a1[8]和二维数组a2[4][8],查看各个表达式的类型、地址、与首地址的差值,以及内存地址内存储的int变量值。数组内变量的低8位记录数组的行号和列号,其中高4位为行,低4位为列。先看一下测试程序给出的结果。 一维数组 1int a1[8]; 2sizeof(a1): 32(0x20) var typeof(var) (void *)(var) offset *(int *)(var) a1 int * 0x7ffe2034d2d0 0x00 0x00 &a1 int (*)[8] 0x7ffe2034d2d0 0x00 0x00 &a1[0] int * 0x7ffe2034d2d0...