Embedded software engineer job written examination, interview questions (1)

I. Introduction

Recently, I am looking for an embedded software development position. Because I am facing autumn recruitment for the first time, I am preparing to write a long article to record some questions about C language that may be asked and tested.

Two, classic interview questions


Stack

The difference between memory space distribution and stack

Process and thread

The difference between process and thread

Preprocessing and macros

  1. Use the preprocessing directive #define to declare a constant to indicate how many seconds are in a year (leap years are not considered)

    #define SECONDS_PER_YEAR (60*60*24*365)UL

    This calculation will overflow the integer number of the 16-bit machine, and it is not negative, so you need to use the unsigned long integer UL

  2. Write a standard macro MIN, this macro enters two parameters and returns the smaller one
    #define MIN(A,B) ((A)<=(B)?(A):(B))

  3. The difference between #define and typedef

    #define and typedef difference and usage

  4. The use of # and ## in macro definition

    Use and difference between # and ## in C language macro definition

  5. The purpose of preprocessor identification #error, #warning

     #error:用于产生一个编译的错误信息,并停止编译
     #warning:用于产生一个编译的警告信息
    

Bit manipulation

Set the nth bit of a to 0 and clear it:

  • 置1: a|=(0x1<<n);
  • 清0:a&=~(0x1<<n);

For example:

#define		BIT3	(0x1<<3)

static int a;
// 置1
void Set_Bit3(void)
{
    
    
	a |= BIT3;
}
// 置0
void Clear_Bit3(void)
{
    
    
	a &= ~BIT3;
}

Big endian little endian:

  • Big endian: The high bit of data is stored in the low address of the memory, and the low bit of data is stored in the high address of the memory.

  • Little endian: The high bit of data is stored in the high address of the memory, and the low bit of data is stored in the low address of the memory.

    For example, 0x1234 is stored in the address starting position as 0x4000

    Big endian:

    Memory address data
    0x4001 0x34
    0x4000 0x12

    Little endian:

    Memory address data
    0x4001 0x12
    0x4000 0x34

cycle

Endless loop
// 两种写法
for(;;);
while(true);

After compilation, for(;;)there are fewer instructions, no registers, and no judgment jump. Compared with the while(true) loop, it is more concise and more efficient.

The difference between do...while and while...do

Answer: The previous cycle will be judged again, and the latter judgment will be cycled again.

Data declaration

  • Use variable a to give the following definition
    • a) an integer

    • b) A pointer to an integer

    • c) A pointer to a pointer, the pointer it points to is an integer

    • d) An array of 10 integers

    • e) An array with 10 pointers, the pointer points to an integer type (array of pointers)

    • f) A pointer to an array of 10 integers (array pointer)

    • g) A pointer to a function that has an integer parameter and returns an integer

    • h) An array with 10 pointers, the pointer points to a function, the function has an integer parameter, and returns an integer number

      a) int a;
      b) int *a;
      c) int **a;				//二维指针
      d) int a[10];	
      e) int *a[10];			//指针数组
      f)  int (*a)[10];		//数组指针
      g) int (*a)(int);		//函数指针
      h) int (*a[10])(int);	//函数指针数组
      
      //扩展
      int(*a); 		//把指针a取值,并且转换成 int
      (int *) a;		//把a变量转换为 int *
      

Static

  • What is the role of the keyword static?
    • In the function body, a variable declared as static keeps its value unchanged while the function is being called.
    • In the module (but outside the function), a variable declared as static can be accessed by all functions in the module, but not by other functions outside the module. It is a local global variable.
    • In a module, a function declared as static can only be called by other functions in this module. This function is restricted to the local scope of the module where it is declared

Const

The keyword const means: "read-only"

Statement meaning:

a) const int a;			//常整数
b) int const a;	
c) const int *a;		//指向常整数的指针
d) int * const a;		//常量指针
e) int const *a const;	//指向常整数的常指针
  • a), b) The first two functions are the same, a is a constant integer number
  • c) a is a pointer to a constant integer (that is, an integer cannot be modified , but the pointer can be modified )
  • d) a is a constant pointer to an integer ( the integer pointed to by the pointer can be modified , but the pointer cannot be modified )
  • e) a is a constant pointer to a constant integer ( it cannot be modified , the integer pointed to by the pointer cannot be modified, and the pointer cannot be modified)

effect:

  1. The function of the keyword const is to convey very useful information to people who read your code. In fact, declaring a parameter as a constant is to tell the user the application purpose of the parameter.
  2. By giving the optimizer some additional information, using the keyword const may make the code more compact
  3. Reasonable use of the keyword const can make the compiler naturally protect those parameters that do not want to be changed and prevent them from being unintentionally modified .

Volatile

The meaning of the keyword volatile:
A variable defined as volatile means that this variable may be changed unexpectedly , so that the compiler will not assume the value of this variable.
In other words, the optimizer must carefully re-read the value of this variable every time it uses this variable instead of using the backup stored in the register.
Embedded system programmers often deal with hardware, interrupts, and RTOS, all of which require volatile variables.
Here are a few examples:

  1. Hardware registers of parallel devices (such as status registers)
  2. Non-automatic variables that will be accessed in an interrupt service subroutine (Non-automatic variables)
  3. Variables shared by several tasks in multi-threaded applications
problem
  1. Can a parameter be either const or volatile? why

    Answer: Yes, such as read-only status register. It is volatile because it may be changed unexpectedly, and it is const because the program should not try to modify it.

  2. Can a pointer be volatile? why

    Answer: Yes, although not often. An example is when an interrupt service routine modifies a pointer to a buffer.

  3. What is wrong with the following function?

    int square(volatile int *ptr)
    {
          
          
    	return *ptr * *ptr;
    }
    

    Answer: The purpose of this code is to return the pointer *ptr to point to the value squared. However, because *ptr points to a volatile parameter, the compiler will generate code similar to the following:

    int square(volatile int *ptr)
    {
          
          
    	int a,b;
    	a = *ptr;
    	b = *ptr;
    	return a*b;
    }
    

    Since the value of *ptr may be unexpectedly changed, because the values ​​of a and b may be different, the result is not a squared value either.
    The correct code is as follows:

    long square(volatile int *ptr)
    {
          
          
    	int a;
    	a = *ptr;
    	return a * a;
    }
    

pointer

  1. It is often necessary to access a specific memory location in an embedded system . For example, it is required to set the value of an integer variable with an absolute address of 0x67a9 to 0xaa66.
    Test whether you know that it is legal to force an integer data to be converted into a pointer in order to access an absolute address . A typical similar code is as follows:
//第一种方式(建议)
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa66;

//第二种方式(比较难理解)
*(int *const)(0x67a9) = 0xaa66;

Interrupt

Interrupts are an important part of embedded systems, leading many compiler developers to provide an extension to enable standard C to support interrupts. The most representative fact is that a new keyword is generated. __interrupt
The following code uses the __interrupt keyword to define an interrupt service routine (ISR). Please comment on this code:

__interrupt double computer_area(double radius)
{
    
    
	double area = PI * radius * radius;
	printf("Area = %f",area);
	return area;
}

Reply:

  • 1). ISR cannot return a value and pass parameters . If you don't understand this, you won't be hired.
  • 2). In many processors/compilers, floating point numbers are generally not reentrant. Some processors/compilers require extra registers to be pushed onto the stack, and some do not allow floating point operations in ISRs.
  • 3). The ISR should be short and efficient . Therefore, it is not suitable for complex floating-point operations and printf() with reentrancy and performance issues.

Code example

  1. What is entered in the following code? why?
    void foo(void)
    {
          
          
    	unsigned int a = 6;
    	int b = -20;
    	(a+b > 6) ? puts(">6") : puts("<=6");
    }
    
    输出是:>6
    
    Answer: This involves the principle of automatic conversion of integers in the C language. The reason is that when there are both signed type (int) and unsigned type (unsigned int) in the expression, all operands are automatically converted to unsigned type, so -20 becomes a very large positive integer, so the output >6.

Guess you like

Origin blog.csdn.net/qq_30722795/article/details/108113357