Super long! Analysis and solutions to 16 classic C language problems (Collection)

Time:2021-9-13
Super long! Analysis and solutions to 16 classic C language problems (Collection)

Source: https://segmentfault.com/a/1190000038292644

1. Declare a constant with the preprocessing instruction #define to indicate the number of seconds in a year (ignoring leap years)

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

I want to see a few things here:

  • #Basic knowledge of define syntax (e.g. cannot end with semicolon, use of parentheses, etc.)
  • Understand that the preprocessor will calculate the value of the constant expression for you. Therefore, it is clearer and costless to write directly how you calculate the number of seconds in a year rather than the actual value.
  • Realize that this expression will overflow a 16 bit integer – so use the long integer symbol l to tell the compiler that this constant is a long integer.
  • If you use UL (for unsigned long integers) in your expression, you have a good starting point. Remember, first impressions are important.

2. Write a “standard” macro min, which inputs two parameters and returns the smaller one.

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

This test is designed for the following purposes:

  • Identifies #define the basics of its application in macros. This is very important because until the inline operator becomes a part of standard C, macros are the only way to easily generate embedded code. For embedded systems, embedded code is often a necessary method in order to achieve the required performance.
  • Knowledge of triple conditional operators. The reason why this operator exists in C language is that it enables the compiler to produce more optimized code than if then else. It is important to understand this usage.
  • Know how to carefully enclose parameters in parentheses in macros
  • I also use this question to start discussing the side effects of macros, such as: what happens when you write the following code? least = MIN(*p++, b);

3. What is the purpose of preprocessor identification #error?

If you don’t know the answer, please refer to the references

This question is very useful to distinguish a normal guy from a nerd. Only nerds will read the appendix of C language textbook to find out the answers to such questions. Of course, if you’re not looking for a nerd, candidates had better hope that they don’t know the answer.

Xiaobian recommends a studentClanguage/C++Learning skirt【 712284705], whether you are Daniel or Xiaobai, want to change careers or enter a career, you can come to understand, make progress and learn together! There are development tools in the skirt, and many dry goods and technical data are shared!

 

4. Infinite loop is often used in embedded system. How do you write an infinite loop in C?

There are several solutions to this problem. My preferred solution is:

Some programmers prefer the following scheme:

This implementation makes me embarrassed because the syntax doesn’t exactly express what’s going on. If a candidate gives this as a plan, I will use this as an opportunity to explore the basic principles of their doing so. If their basic answer is, “I was taught to do this, but I never thought of why,” it will leave a bad impression on me.

The third scheme is to use goto

If the candidate gives the above scheme, it shows that either he is an assembly language programmer (which may be a good thing) or he is a basic / Fortran programmer who wants to enter a new field.

Super long! Analysis and solutions to 16 classic C language problems (Collection)

5. Give the following definition with variable a

a) An integer

b) A pointer to an integer

c) A pointer to a pointer that points to an integer (a pointer to a pointer to an integer)

d) An array of 10 integers

e) An array of 10 pointers to integers

f) A pointer to an array of 10 integers

g) A pointer to a function that takes an integer as an argument and returns an integer

h) An array of ten pointers to functions that take an integer argument and return an integer

The answer is:

a) int a; // An integer

b)int *a; // A pointer to an integer

c) int **a; // A pointer to a pointer to an integer

d) int a[10]; // An array of 10 integers

e) int *a[10]; // An array of 10 pointers to integers

f) int (*a)[10]; // A pointer to an array of 10 integers

g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer

h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer

People often claim that there are several questions here that can only be answered by turning a book. I agree with this statement. When I wrote this article, I did check the book to make sure the grammar was correct.

But when I am interviewed, I expect to be asked this question (or similar). Because during the interview, I’m sure I know the answer to this question. If the candidate doesn’t know all the answers (or at least most of the answers), he doesn’t prepare for the interview. If the interviewer doesn’t prepare for the interview, why can he prepare?

6. What is the function of the keyword static?

Few people can answer this simple question completely. In C language, the keyword static has three obvious functions:

  • In the function body, a variable declared static maintains its value during the call of the function.
  • In the module (but outside the function), a variable declared as static can be accessed by the function used in the module, but cannot be accessed by other functions outside the module. It is a local global variable.
  • In modules, the first mock exam is called static function, and can only be called by other functions in this module. That is, this function is restricted to the local scope of the module that declares it.

Most candidates can correctly answer the first part, some can correctly answer the second part, and few people can understand the third part. This is a serious disadvantage of a candidate because he clearly does not understand the benefits and importance of localizing data and code scope.

7. What does the keyword const mean?

As soon as I heard the interviewee say, “const means constant”, I knew I was dealing with an amateur. Last year, Dan Saks completely summarized all the uses of const in his article, so every reader of ESP (embedded systems programming) should be very familiar with what const can and can’t do. If you never read that article, just say that const means “read-only”. Although this answer is not a complete answer, I accept it as a correct answer. (if you want a more detailed answer, read Saks’s article carefully.) if the candidate can answer this question correctly, I will ask him an additional question: what do the following statements mean?

The first two functions are the same. A is a constant integer number. The third means that a is a pointer to a constant integer (that is, an integer is not modifiable, but the pointer can). The fourth meaning a is a constant pointer to an integer (that is, the integer pointed to by the pointer can be modified, but the pointer cannot be modified). The last one means that a is a constant pointer to a constant integer (that is, the integer pointed to by the pointer is not modifiable, and the pointer is not modifiable).

If the candidate can answer these questions correctly, he will leave a good impression on me. By the way, you may ask, even if you don’t use the keyword const, it’s still easy to write programs with correct functions. So why do I pay so much attention to the keyword const? I also the following reasons:

  • The function of const keyword is to convey very useful information to those who read your code. In fact, declaring a parameter as a constant is to tell the user the application purpose of this parameter. If you spend a lot of time cleaning up the garbage left by others, you will soon learn to thank this redundant information. (of course, programmers who know how to use const rarely leave garbage for others to clean up.)
  • By giving the optimizer some additional information, using the keyword const may produce more compact code.
  • Reasonable use of the keyword const can make the compiler naturally protect those parameters that do not want to be changed from unintentional code modification. In short, this can reduce the occurrence of bugs.

There is a good memory method, such as const char * A. by rotating clockwise, you can see that const is closest to a, that is, const modifies constant a

If the const keyword does not involve pointers, we can understand that the following is the case involving pointers:

If you can distinguish the above four situations, Congratulations, you have taken a gratifying step. I don’t know. It doesn’t matter. We can refer to Item21 in effective c + +. If const is on the left side of the asterisk, const is used to modify the variable pointed to by the pointer, that is, the pointer is a constant; If const is to the right of the asterisk, const modifies the pointer itself, that is, the pointer itself is a constant. Therefore, the case of [1] and [2] is the same. The content pointed to by the pointer is a constant (const is independent of the position of the variable declarator). In this case, it is not allowed to change the content, such as * a = 3; [3] The pointer itself is a constant and the content pointed to by the pointer is not a constant. In this case, the pointer itself cannot be changed. For example, a + + is wrong; [4] The pointer itself and the content pointed to are constants.

Super long! Analysis and solutions to 16 classic C language problems (Collection)

8. What is the meaning of the keyword volatile and give three different examples.

A variable defined as volatile means that the variable may be changed unexpectedly, so that the compiler will not assume the value of the variable. To be precise, when using this variable, the optimizer must carefully reread the value of this variable every time, rather than using the backup stored in the register. Here are some examples of volatile variables: 1). Hardware registers of parallel devices (such as status registers)

2) . non automatic variables that will be accessed in an interrupt service subroutine

3) . variables shared by several tasks in multithreaded applications

People who can’t answer this question won’t be hired. I think this is the most basic problem to distinguish C programmers from embedded system programmers. Embedded system programmers often deal with hardware, interrupts, RTOS, etc., which require volatile variables. Failure to understand volatile content will lead to disaster.

Assuming that the interviewee correctly answers this question (well, I doubt whether it will be so), I’ll go a little deeper to see if this guy directly understands the importance of volatile.

1) Can a parameter be const or volatile? Explain why.

2) Can a pointer be volatile? Explain why.

3) . what is wrong with the following function:

Here are the answers:

1) Yes. An example is a read-only status register. It is volatile because it can be changed unexpectedly. It is const because the program should not try to modify it.

2) Yes. Although this is not very common. An example is when a service subroutine modifies a pointer to a buffer.

3) There is a prank in this code. The purpose of this code is to return pointersPTR points to the square of the value, but becausePTR points to a volatile parameter, and the compiler will generate code similar to the following:

Since the value of * PTR may be unexpectedly changed, a and B may be different. As a result, this code may not return the square value you expect! The correct code is as follows:

9. Embedded systems always require users to perform bit operations on variables or registers. Given an integer variable a, write two pieces of code. The first one sets bit 3 of a and the second clears bit 3 of A. In the above two operations, keep the other bits unchanged.

There are three basic reactions to this problem

1) I don’t know how to do it. The respondent has never done any embedded system work.

2) . use bit fields. Bit fields is something thrown into the dead corner of C language. It not only ensures that your code is not portable between different compilers, but also ensures that your code is not reusable. Unfortunately, I recently saw the driver written by Infineon for its more complex communication chip. It uses bit fields, so it is completely useless to me, because my compiler implements bit fields in other ways. Morally speaking: never let a non embedded guy stick to the edge of actual hardware.

3) . operate with #definitions and bit masks. This is a highly portable method and should be used. The best solution is as follows:

Some people prefer to define a mask for setting and clearing values, and it is also acceptable to define some description constants. I’d like to see a few key points: explain the constants, | = and & = ~ operations.

 

10. Embedded systems often require programmers to access a specific memory location. In a project, it is required to set the value of an integer variable with an absolute address of 0x67a9 to 0xaa66. The compiler is a pure ANSI compiler. Write code to accomplish this task.

This question tests whether you know that it is legal to cast an integer to a pointer in order to access an absolute address. The implementation of this problem varies with individual styles. Typical similar codes are as follows:

An obscure method is: * (int * const) (0x67a9) = 0xaa55;

Even if your taste is closer to the second option, I suggest you use the first option in the interview.

11. Interrupt is an important part of embedded system, which leads many compiler developers to provide an extension to make standard C support interrupt. The specific fact represented is that a new keyword is generated__ interrupt。 The following code is used__ Interrupt keyword defines an interrupt service subroutine (ISR). Please comment on the of this code.

There are so many errors in this function that people don’t know where to start:

1) . ISR cannot return a value. If you don’t understand this, you won’t be hired.

2) . ISR cannot pass parameters. If you don’t see this, your chances of being hired are equal to the first.

3) Floating point is generally non reentrant in many processors / compilers. Some processors / compilers need to stack the registers at the amount. Some processors / compilers just don’t allow floating-point operations in ISR. In addition, ISR should be short and efficient. It is unwise to do floating-point operation in ISR.

4) In line with the third point, printf () often has reentry and performance problems. If you lose the third and fourth points, I won’t be too difficult for you. Needless to say, if you can get the last two points, your employment prospects will be brighter and brighter.

Super long! Analysis and solutions to 16 classic C language problems (Collection)

12. What is the following code output and why?

This question tests whether you understand the automatic integer conversion principle in C language. I find that some developers know very little of these things. In any case, the answer to this unsigned integer problem is that the output is “> 6”. The reason is that when signed and unsigned types exist in the expression, all operands are automatically converted to unsigned types.

Therefore, – 20 becomes a very large positive integer, so the result of this expression is greater than 6. This is very important for embedded systems that should frequently use unsigned data types. If you answer this question wrong, you will be on the verge of not getting the job.

13. Evaluate the following code snippets:

The above code is incorrect for a processor with int type other than 16 bits. It should be written as follows: unsigned int compzero = ~ 0;

This question really reveals whether the candidate understands the importance of processor word length. In my experience, good embedded programmers understand the details and limitations of hardware very accurately, but PC programs often regard hardware as an unavoidable trouble.

At this stage, candidates are either completely depressed or full of confidence. If the candidate is obviously not very good, the test ends here. But if it is obvious that the candidate is doing well, I will throw the following additional questions. These questions are difficult. I think only very excellent candidates can do well. When asking these questions, I hope to see more the candidates’ ways to deal with the questions rather than the answers. Anyway, think of it as this entertainment

14. Although not as common as non embedded computers, embedded systems still have the process of dynamically allocating memory from the heap. So what are the possible problems of dynamic memory allocation in embedded systems?

Here, I expect candidates to mention memory fragmentation, fragment collection, variable holding time, etc. This topic has been widely discussed in ESP magazines (mainly P.J. plauger, whose explanation is far more than any explanation I can mention here), so look back at these magazines! After giving the candidate a false sense of security, I took out such a small program: what is the output of the following code fragment and why?

This is an interesting question. Recently, a colleague of mine inadvertently passed the value of 0 to the function malloc and got a legal pointer, I thought of this problem. This is the above code. The output of this code is “got a valid pointer”. I’ll use this to start discussing such a question and see if the interviewee thinks the library routine is right to do so. Getting the right answer is important, but the way to solve the problem and the basic principle of your decision are more important.

15. Typedef is frequently used in C language to declare synonyms of an existing data type. You can also use a preprocessor to do similar things. For example, consider the following example:

The intention of the above two cases is to define DPS and TPS as a pointer to the structure s. Which method is better? (if any) why? This is a very delicate question. Anyone who answers this question correctly (for legitimate reasons) should be congratulated. The answer is: typedef is better. Consider the following example:

The first extension is: struct s * P1, P2; The above code defines P1 as a pointer to the structure and P2 as an actual structure, which may not be what you want. The second example correctly defines P3 and P4 pointers.

16. C language agrees with some shocking structures. Is the following structure legal? If so, what does it do?

This question will be a happy ending to the test. Believe it or not, the above example is completely grammatical. The question is how does the compiler handle it? Low level compilers will actually debate this issue. According to the best processing principle, the compiler should be able to handle all legitimate uses as much as possible. Therefore, the above code is processed as: C = a + + + B; Therefore, this code holds a = 6, B = 7, C = 12. If you know the answer, or guess the right answer, well done. If you don’t know the answer, I don’t take this as a question. I found that the biggest advantage of this problem is that it is a good topic about code writing style, code readability and code modifiability.

 

If you encounter difficulties in self-learning C language, you want to find oneC language learning environment, you can join usC / C + + technology exchange group, click me to join~It will save a lot of time and overcome many problems encountered in learning with the help of professional cattle.