linux kernel 编程基础

一、C语言系列(计算型):

1、数据类型 int占4byte  char占1byte  (32bit的系统),求下面sizeof的大小:

(1)sizeof练习
    char str[] = "Hello";              sizeof(str) = 6;
	char *p = str;                    sizeof(p) = 1;
	void *pbuf = malloc(100);		sizeof(pbuf) = 4;
	void func(char string[100])		
	{
		int a = sizeof(string);        sizeof(a) = 4;
	}

	char *src = "world"; 
    int len = strlen(src);            len = 5;
(2)结构体对齐
typedef struct{
		char a;
		int b;
		char c;
	}test_struct;

	test_struct  g_test_array[5];
	
	请问:  sizeof(test_struct) = 12;
		sizeof(g_test_array) = 60;

2、请计算如下结果:

(1)int  i=1, j = 2;

          int k = i +++j

          k = 3  //先执行i + j = 3, 然后执行i ++

(2) j = 3 * 3 = 9

    product(i ++) = i ++   *   i ++   //此时i = 5

    product(++ i ) = ++i  *   ++i =  7  *  7 = 49

#define  product (x)  (x*x)
int main()
{
    int i = 3,j,k;
    j = product(i ++);
    k = product(++j);
    printf("j = %d,k = %d\n",j,k);
}

(3)uint 型数据和int 型数据运行后,自动转换为uint类型数据,-14转为uint很大:c > 1

char foo(void){
    unsigned int a = 6;
    int b = -20;
    char c = ;
    (a + b > 6)?(c = 1):(c = 0)
}

(4)a = b + 2 * b + 2 = 11

#define SQR(x)  (x*x)
void main(){
    int a,b = 3;
    a = SQR(b + 2);
  printf("a = %d\n",a)
}

# define  SQR(x)   ((x) * (x))      结果为25

(5)int  **a[3][4]这个数组占据多大空间?

  sizeof问题:3*4*4 = 48

(6)char var[10]

  int  test(char  var[]){

  return sizeof(var); //var[]等价于*var ,结果为4

  }

(7)计算结果:

#include<stdio.h>
int main(){
    printf("%f",5);   //0.000000
    printf("%d",5.01);//是一个大数
}

3、程序实现:已知从1-100 范围内挑选99个整数,没有顺序的
    存储在全局数组a中,请编程找出缺少的那个整数。
思路:
    sum1=1+2+3+4+……+100
    sum2=数组元素之和
    sum1-sum2就是没有的那个。

#include <stdio.h>

int sum1_t(void){
	int i = 0;
	int sum1 = 0;
	for(i = 1;i <= 100;i ++){
		sum1 = sum1 + i;
	}
	return sum1;
}

void main(void){
	int sum1 = sum1_t();
	int sum2 = 0;
	int a[99]; //存放无序的字符
	int i = 0;
	printf("sum1 = %d\n",sum1);

	for(i = 0;i < 99;i ++){
		sum2 = sum2 + a[i];
	}
	diff = sum1 - sum2;
	//diff 是缺少的数
}

4、有关内存的思考题:

(1)请问运行Test有什么结果?

void GetMemory(char *p){
	p = (char *)malloc(100);
}

void Test(void){
	char *str = NULL;
	GetMemory(str);
    
	strcpy(str,"hello world");
	printf(str);
}

A.编译错误
B.输出"hello world"
C.输出""
D.segmentation fault

选D,调用GetMemory( str )后, str并未产生变化,依然是NULL.
    strcpy 会报错;  

(2)请问运行Test有什么结果?

char *GetMemory(void){
	char p[] = "hello world";
	return p;
}

void Test(void){
	char *str = NULL;
	str = GetMemory();
	printf(str);
}

A. 程序编译错误 B. 输出“hello world” C. 无效的指针,输出不确定 D. 输出“NULL”

选C 因为p的生命周期在GetMemory函数执行完了就被销毁了,str 指向的是个野指针;

(3)请问运行Test有什么结果?

void GetMemory2(char **p, int num){
	*p = (char *)malloc(num);
}

void Test(void){
	char *str = NULL;
	GetMemory(&str, 100)
	strcpy(str, "100");
	printf(str);
}

结果:100

(4)请问运行Test有什么结果?

void Test(void){
	char *str = (char *)malloc(100);
	
	strcpy(str, "hello");
	free(str);
	
	if(str != NULL){
		strcpy(str, "world");
		printf(str);
	}
}

user after free 野指针,不确定的异常;

13、用C语言写一个strcat函数char  *mystrchar(char *dest, char *source):

#include <stdio.h>
#include <stdlib.h>
char *mystrcat(char *dest, char *source)
{
    char *ptr = dest;
    if (dest == NULL || source == NULL)
    {
        printf("the input string is error!\n");
        return NULL;
    } 
    while (*dest != '\0')
        dest ++;
    while ((*dest++ = *source++) != 0 );

    return ptr;
}

5、一个字符串在另外一个字符串中出现的次数统计:

  

6、排序:

(1)冒泡排序:

#include <stdio.h>
#define SIZE 8
 
void bubble_sort(int a[], int n);
 
void bubble_sort(int a[], int n)
{
    int i, j, temp;
    for (j = 0; j < n - 1; j++)
        for (i = 0; i < n - 1 - j; i++)
        {
            if(a[i] > a[i + 1])
            {
                temp = a[i];
                a[i] = a[i + 1];
                a[i + 1] = temp;
            }
        }
}
 
int main()
{
    int number[SIZE] = {95, 45, 15, 78, 84, 51, 24, 12};
    int i;
    bubble_sort(number, SIZE);
    for (i = 0; i < SIZE; i++)
    {
        printf("%d\n", number[i]);
    }
    return 0;
}

(2)快速排序:

void sort(int *a, int left, int right)
{
    if(left >= right)/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/
    {
        return ;
    }
    int i = left;
    int j = right;
    int key = a[left];
     
    while(i < j)                               /*控制在当组内寻找一遍*/
    {
        while(i < j && key <= a[j])
        /*而寻找结束的条件就是,1,找到一个小于或者大于key的数(大于或小于取决于你想升
        序还是降序)2,没有符合条件1的,并且i与j的大小没有反转*/ 
        {
            j--;/*向前寻找*/
        }
         
        a[i] = a[j];
        /*找到一个这样的数后就把它赋给前面的被拿走的i的值(如果第一次循环且key是
        a[left],那么就是给key)*/
         
        while(i < j && key >= a[i])
        /*这是i在当组内向前寻找,同上,不过注意与key的大小关系停止循环和上面相反,
        因为排序思想是把数往两边扔,所以左右两边的数大小与key的关系相反*/
        {
            i++;
        }
         
        a[j] = a[i];
    }
     
    a[i] = key;/*当在当组内找完一遍以后就把中间数key回归*/
    sort(a, left, i - 1);/*最后用同样的方式对分出来的左边的小组进行同上的做法*/
    sort(a, i + 1, right);/*用同样的方式对分出来的右边的小组进行同上的做法*/
                       /*当然最后可能会出现很多分左右,直到每一组的i = j 为止*/
}

7、写一个十进制数转换为八进制的程序:

(1)十进制转八进制:

#include <stdio.h>
#define N 8
void tran(int num,int k)
{
    int arr[N],i;
    for (i=0;i <N;i++)
    {
        arr[i]=num%k;
        num=num/k;
        if (num==0)
            break;
    }
    printf("转换为%d进制数为: ",k);
    printf("\n\n\n");
}

(2)八进制转十进制:

二、C语言系列(定义型):

1、写一个标准宏MIN ,这个宏输入两个参数并返回较小值:

  #define  MIN(A,B)    ((A) <= (B)?(A):(B))

2、下面的函数有问题吗?Volatile 关键字在什么情况下使用?
    int square(volatile int *ptr){
        return (*ptr) * (*ptr);
    }

    (1)由于*ptr的值可能在两次取值语句之间发生改变,这段代码可能返回的不是你所期望的平方值,
    正确:
        long square(volatile int*ptr){
            int a;
            a = *ptr;
            return a*a;
        }
    
    (2)防止编译器优化,每次都是从寄存器中读取数据,该数据不会因其他线程改变而改变;

   中断服务函数中的使用;多任务环境下各任务间共享的标志应该加volatile;

   存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。

3、请填写BOOL, float,指针变量 与 "零值" 比较的if 语句,这里的"零值"可以是:0; 0.0; FALSE,空指针

(1)请写出BOOL flag 与"零值" 比较的if 语句:
  if (flag == FALSE){
  }

(2)请写出float x 与"零值" 比较的if 语句:
  if(x == 0.0){
  }

(3)请写出char *p 与"零值" 比较的if 语句:
  if(*p == NULL){
  }

4、const 有什么用途?(至少说明两种)
(1)可以定义const常量,具有不可变性。 
  例如:const int Max=100; Max++会产生错误; 
(2)可以定义参数、返回值等,可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。
 

5、用预处理指令#define 声明一个常数,用以表明1年中国有多少秒?
    #define YEARS_SECOND  (365*24*60*60)UL
 

6、static的全局变量和全局变量的区别?static的局部变量和普通变量的区别?

局部变量分配在什么区域?

(1)全局变量改变为静态变量后改变了他的作用域,限制了它的作用范围为本文件;

(2)局部变量改为静态变量后改变了他的生存期,函数结束,生命期结束;

(3)局部变量分配在栈区(用于存放函数的参数,局部变量的值等);
 

7、如何在C中初始化一个字符数组:

  逐个字符串赋值:char s[] = {'a', 'b', 'c', 'd'};

  字符串赋值: char s[] = {"ABCD"};

  对于二维字符数组:char s[2][10] = {"cheng","jinzhou"};

8、如何在C中为一个数组分配空间:

(1)栈形式:Type s[N] 定义后自动分配空间;

(2)堆形式:Type *s = (Type *)malloc(sizeof(Type)*N);

9、如何初始化一个指针数组和数组指针:

(1)指针数组:

  数组里存储的是指针,如int *s[5] 表示数组s里存储了5个指向整型的指针;

  char *s[3] = {"a","bb","ccc"};//表示数值s里面存储3个指向字符型的指针

(2)数组指针:

  其实就是数组,里面存放的是数据,与二维数组一起使用:

  int (*s)[5] 表示数组s里面存储了5个整型数据,等同:int s[5][5]。

10、s[10] 的另外一种表达方式是什么?

  *(s+10)

  二维数组s[5][8] 的表达方式为:*(*(s + 5) + 8)

11、const与#define 有什么区别:

(1)const 常量有数据类型,宏常量没有数据类型;

(2)const变量编译器可以进行类型检查,而#define 只做类型替换;

12、用变量a给出下面的定义:

(1)一个整型数: int  a;

(2)一个指向整型数的指针:int  *a;

(3)一个指向指针吃的指针,它指向的指针是指向的整型数:int  **a;

(4)一个有10个整型数的数组:int a[10];

(5)一个有10个指针的数组,该指针是一个指向一个整型数的:int (*a)[10];

(6)一个指向有10个整型数数组的指针:int  *a[10];

(7)一个指向函数的指针,该函数有一个整型参数并返回一个整型数int  (*a)(int):

(8)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数:int (*a[10])(int);

13、x = x + 1;x += 1;x ++哪个效率最高?

  x = x + 1 //先取x地址中的值,然后再 + 1操作,再赋值给左边x,效率最低;

  x += 1 // 读取右x地址的值,进行 x + 1;

  x ++  //效率最高,读取右x的地址,x自增1。

二、linux内核基础:

1、嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型
    变量a,写两段代码,第一个设置a的bit位3,第二个清除a的bit 3,
    在以上两个操作中,要保持其他位不变,另外代码要对16位和32位
    系统可以通用。

    #define BIT3 (0x1 << 3)
    static int a;
    void set_bit3(void)
    {
        a |= BIT3;
    }
    void clear_bit3(void)
    {
        a &= ~BIT3;
    }

2、linux中mutex_lock函数的作用是什么?spin_lock函数的作用是什么?
    两者的区别是什么?

   (1)mutex_lock可睡眠的互斥锁,保护临界资源,同一时刻;

  (2)spin_lock自旋锁,保护临界资源,临界区不可以睡眠,常用于中断上下文;

3、linux驱动中platform bus device driver四个概念,例如经常用的函数platform_driver_register,

bus_add_driver和bus_add_device等,如何理解platform bus device driver这四个概念,他们

分别的作用是什么?他们之间有什么关系?

总线(bus),驱动(driver),设备(device)这三者之间的关系就是:

驱动开发者可以通过总线(bus)来将驱动(driver)和设备(device)进行隔离,这样的好处就是

开发者可以将相对稳定不变的驱动(driver)独立起来,可以通过总线(bus)来桥接与之匹配的设

备(device),设备(device)只需要提供与硬件相关的底层硬件的配置,如io,中断等。

4、头文件中的ifndef/define/endif干什么用?
    防止重复定义宏和重复包含头文件
 

5、#include<filename.h> 和 #include "filename.h" 有什么区别?
    #include<filename.h>系统检索头文件时 会先从系统文件里开始找,再找其他地方。用于系统文件较快。
    #include"filename.h"系统检索头文件时先从程序所处目录开始查找,用于自定义文件较快。
 

6、以下嵌入式系统的一段中断函数,请指出该函数中的错误:
__interrupt double compute_area(double radius){
    double area = PI * radius * radius;
    printf("Area = %f",area);
    return(area);
}

(1)中断函数不能传参数;

(2)printf有重入和性能上的问题,不在中断函数中使用;

(3)中断函数不能返回一个值;

(4)一般不在中断函数中做浮点运算。

7、heap和stack的差别是什么?

  heap是堆,stack是栈,

  stack的空间由操作系统自动分配/是否,heap上的空间需要手动分配/释放;

  stack空间空间有限,heap是很大的自由区域。

  malloc分配的内存在堆上,程序在编译期对变量和函数分配的内存都在栈上,运行过程中传递

  的参数也是在栈上运行。

8、简约Linux或Android 软件框架图并做一些描叙;

9、linux下,防止并发执行的机制有哪些,让工作推后执行的方式有哪些。
    原子操作
    自旋锁
    信号量
    互斥锁

10、请列出 IIC,SPI,UART各几根线,分别是什么?
  i2c   scl   sda
  SPI   cs  clk  SDI  SDO
  uart  tx  rx  vcc  GND

11、请大致说出android系统中TP驱动的probe函数做了哪些工作?
  上电
  注册input设备
  注册中断

  初始化相关硬件参数

  I2C子系统注册

12、Uboot在引导linux内核要做哪些事情,请简要列出?
  第一步是将内核镜像从启动介质中加载到DDR中
  第二步是去DDR中启动内核镜像
  通过cmdline 传递需要的参数

13、进程的生命周期:

作者:frank_zyp 
您的支持是对博主最大的鼓励,感谢您的认真阅读。 
本文无所谓版权,欢迎转载。

猜你喜欢

转载自blog.csdn.net/frank_zyp/article/details/87859415