Embedded software classic interview questions

Preprocessor

Use the preprocessing command #define to declare a constant to indicate how many seconds there are in a year (ignore the leap year problem)

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

Test points
1) #define basics of grammar
2) Understand that the preprocessor will calculate the value of a constant expression for you, so directly write out how many seconds in a year you have determined instead of calculating the actual value. There is no price to be clearer.
3) Realize that this expression will use a 16-bit machine integer overflow, so the integer symbol L must be used to tell the compiler that this is a long integer value.
4) If you use UL (Unsigned Long Integer) in your expression, it indicates that there is a good compiling habit
. The role of #define
allows an identifier to represent a string in a C or C++ language source program, called As "macro". The identifier defined as "macro" is called "macro name". When compiling and preprocessing, all occurrences of "macro names" in the program are replaced with strings in the macro definition, which is called "macro substitution" or "macro expansion". The macro definition is completed by the macro definition command in the source program. Macro substitution is automatically completed by the preprocessing program. "Macro" is divided into two types: with parameters and without parameters. It can also prevent duplication of definitions.

#difine M (a)+(b)
M*M= (a)+(b)*(a)+(b)

The above example reminds us that we need to pay attention
to the use of brackets. Also pay attention to the macro definition:
  1. The preprocessor does not check it. If there is an error, it can only be found when compiling the source program that has been expanded by the macro.
  2. The macro definition is not a description or a statement. It is not necessary to add a semicolon at the end of the line. If a semicolon is added, even the semicolon will be replaced together.
  3. The macro definition must be written outside the function, and its scope is from the macro definition command to the end of the source program. To terminate its scope, use the #undef command.

"Standard" Macro MIN

This macro takes two parameters and returns the smaller one

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

1) Know how to carefully enclose parameters in parentheses in macros.
2) Pointer out-of-bounds may be a serious problem
3) Understand the side effects of macros
Examples:

least=MIN(*p++,b)

Those who are interested can practice on their own

Preprocessor ID#error

When the preprocessor preprocesses to the #error command, it will stop compiling and output a user-defined error message.
Usage example:
Check whether the compiler compiling this source file is a C++ compiler.
If a C language compiler is used, execute #error Command
If you are using a C++ compiler, skip the #error command

Endless loop

while1{
    
    }
for(;;)
{
    
    }
goto

Loop

Comparison of 1 and 2:
for (;;) two in the infinite loop;; represents two empty statements, and the compiler generally optimizes them and enters the loop body directly. While (1) the 1 in the infinite loop is regarded as an expression, and it is necessary to judge whether the constant 1 is equal to zero every time in the loop. Relatively speaking, the for-type infinite loop is more efficient. Of course, the above conditions depend on the optimization of the compiler. There is no difference between the two optimizations of some compilers, but not all compilers have made such optimizations.
When executing to "goto code", the program will automatically jump to the character mark following goto, that is, "Loop"... But the "Loop" is located before the "goto" code, so it jumps to the "Loop" code. Going down, you will encounter goto again...This cycle repeats, so it will become an endless loop

Data declaration

Use the variable a to give the following definitions:
1) an integer number
2) a pointer to integer data
3) a pointer to a pointer, which points to an integer number
4) an array of 5 integer numbers
5) An array with 5 pointers, the pointer points to an integer
6) A pointer to an array with 5 integers
7) A pointer to a function, the function has an integer parameter and returns an integer
8) An array with 5 pointers, the pointer points to a function, the function has a pictogram parameter and returns an integer
  
1)

int a;
int *a;
int **a;
int a[5];
int *a[5];
int (*a)[5];

7)

int*a)(int)
{
    
    
}
int (*a[5])(int)
{
    
    
}

static

Three functions:
1) In the body of the function, the defined variable is a static variable. When other functions call the function, its value remains unchanged.
2) In the module, outside the function, the variable is defined as static. It can be accessed by all functions in the module. It is a local global variable.
3) Within the module, a variable declared as static is restricted to functions that cannot be called outside the module.

const

volatile

Bit manipulation

The above three knowledge points are explained in detail in other blogs. Here are other operations:
Use define to define bit operations:
#define BIT(X) (0X01<<(X))
We can use this BIT(X) to set and clear:
set

uint8_t a=0x11;
a|=BIT(3);

Cleared

uint8_t a=0x11;
a&=~BIT(3);

Access memory fixed memory location

It is required to set an integer variable value of absolute address 0x5678 to 0x1234:

int *p;
p=0x5678;
*p=0x1234;

or:

*int *const(0x5678)=0x1234;

Interrupt

1) There can be no parameters in the
interrupt function. 2) There can be no return value in the interrupt function.
3) The interrupt should be as simple as possible. Do not perform floating point operations. Different compilers have different effects. Floating points are generally not reentrant. Print functions printf() often has reentrancy and performance issues.

Integer automatic conversion

unsigned int a=6;
signed int b=-20;
(a+b)>6?puts(">6"):puts("<=6");

The answer is the former!
When there are signed and unsigned types in the expression, all operands are automatically converted to unsigned. So -20 becomes a very large number.

unsigned int zero=0;
unsigned int compzero=0xFFFF;

For compilers that are not 16-bit, the second one should look like this:

unsigned int compzero-~0;

Dynamic memory allocation

There may be memory fragmentation in dynamic memory allocation in the heap.

char *p;
if((p=(char*)malloc(0))==NULL)
puts("null");
else
put("YES");

Will output YES;

typedef

#define D struct s*
typedef struct s *  P

The above two typedefs are better, why?

D D1,D2;
P P1,P2;

The first question is expanded to:

struct s* D1,D2;

Naturally there may be errors

Guess you like

Origin blog.csdn.net/weixin_42271802/article/details/106241084