C Language Testing: 0x10 basic issues that embedded programmers should know
C language testing is an essential and effective way to recruit embedded system programmers. Over the years, I have both participated in and organized many such tests. During this process, I realized that these tests can provide a lot of useful information for both the interviewer and the interviewee. In addition, aside from the interview pressure, this test is also quite interesting.
From the perspective of the subject, you can learn a lot about the problem or invigilator. Is this test designed to show the ANSI standard details rather than technical skills? This
Stupid question? To obtain the ASCII value of a character. Do these questions focus on your system call and memory allocation policy capabilities? This indicates that the topic may not be able to spend time on the microcomputer.
In an embedded system. If the answer to any of the above questions is "yes", I know that I have to seriously consider whether I should do the job.
From the perspective of the interviewer, a test may reveal the examinee's quality in many aspects: the most basic, you can understand the examinee's C language level. Anyway, let's take a look at how this person answers his questions.
The problem is also very interesting. Should the examinee make a wise choice with a good intuition, or is it just blind? When the examinee gets stuck on a problem, is it an excuse or a real curiosity about the problem?
What are opportunities for learning? I found this information as useful as their test scores.
With these ideas, I decided to give some questions that really target embedded systems. I hope these headaches can help people who are looking for a job. I have encountered these problems over the years. Some of these questions are difficult, but they should give you some inspiration.
This test is suitable for candidates of different levels. Most primary-level candidates have poor performance, and experienced programmers should have good performance. In order for you to determine the preference of some questions, no score is assigned for each question. If you choose these questions for your use, please assign scores according to your meaning.
Preprocessor)
1. Use the preprocessing command # define to declare a constant to indicate the number of seconds in a year (ignore the leap year problem)
# Define seconds_per_year (60*60*24*365) UL
Here I want to see several things:
& #8226; # basic knowledge of define syntax (for example, it cannot end with a semicolon or use of parentheses)
& #8226; know how the Preprocessor calculates the value of a constant expression for you. Therefore, you can directly write how many seconds in a year instead of the actual value, it is clearer with no cost.
& #8226; realize that this expression will overflow the integer number of a 16-bit machine-so the long integer sign L is used to tell the compiler that this constant is the long integer number.
& #8226; if you use ul (representing an unsigned long integer) in your expression, you have a good starting point. Remember, the first impression is very important.
2. Write a "standard" macro min, which inputs two parameters and returns a smaller one.
# Define min (A, B) (a) <= (B )? (A): (B ))
This test is intended for the following purposes:
& #8226; identifier # basic knowledge of define application in macros. This is important, because until the inline operator becomes part of standard C, macros are the only way to facilitate the generation of embedded code. For embedded systems, in order to achieve the required performance, embedded code is often a required method.
& #8226; triplicate operator knowledge. The reason for the existence of this operator in C language is that it enables the compiler to produce code that is more optimized than if-then-else. It is important to understand this usage.
& #8226; carefully enclose parameters in brackets in macros
& #8226; I also use this question to discuss the side effects of macros. For example, what happens when you write down the code below?
Least = min (* P ++, B );
3. pre-processor ID # What is the purpose of error?
If you do not know the answer, see References 1. This problem is useful for distinguishing a normal guy from a nerd. Only the nerd can read the appendix of the C language textbook to find the answer to such a question. Of course, if you are not looking for a nerd, you 'd better ask yourself not to know the answer.
Infinite Loops)
4. Infinite loops are often used in embedded systems. How do you write an infinite loop in C?
There are several solutions to this problem. My preferred solution is:
While (1)
{
?}
Some programmers prefer the following solutions:
For (;
{
?}
This implementation method makes me embarrassed because this syntax does not exactly express what is going on. If a candidate provides this solution, I will use this as an opportunity to explore the basic principles of their practice. If their basic answer is: "I was taught to do this, but I never thought of why ." This leaves a bad impression on me.
The third solution is to use GOTO
Loop:
...
Goto loop;
If the candidate gives the above solution, it indicates that he is an assembly language programmer (which may be a good thing) or a basic/Fortran programmer who wants to enter a new field.
Data declarations)
5. Use variable A to give the following definition
A) An integer)
B) a pointer to an integer (a pointer to an integer)
C) a pointer to a pointer pointing to an integer (a pointer to an intege) r
D) an array of 10 integers (an array of 10 integers)
E) an array with 10 pointers pointing to an integer. (An array of 10 pointers to integers)
F) A pointer to an array with 10 integers (a pointer to an array of 10 integers)
G) a pointer to a function. The function has an integer parameter and returns an integer number (a pointer to a function that takes an integer as an argument and returns an integer)
H) An array with 10 pointers pointing to a function that has an integer parameter and returns an integer number (an array of ten)
Pointers to functions that take an integer argument and return
Integer)
The answer is:
A) int A; // an integer
B) int * A; // a pointer to an integer
C) int ** A; // 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 that can be answered only after a book is opened. I agree with this statement. When I wrote this article, I checked the book to confirm the correctness of the syntax. However
When I was interviewed, I expected to be asked this question (or similar questions ). Because I knew the answer to this question during the interview period. If the examinee does not know all the answers (or
If the interviewer is not prepared for the interview, why did he prepare?
Static
6. What is the role of the keyword static?
Few people can answer this simple question completely. In the C language, the keyword static has three obvious functions:
& #8226; In the function body, a variable declared as static remains unchanged during the function call process.
& #8226; Within the module (but in the external body of the function), a variable declared as static can be accessed by the function used in the module, but not by other functions outside the module. It is a local global variable.
& #8226; in a module, a function declared as static can only be called by other functions in the module. That is, this function is restricted to use within the local scope of the module that declares it.
Most of the respondents can answer part 1 correctly. Some of them can answer part 2 correctly. Few people can understand part 3. This is a serious disadvantage of a candidate because he obviously does not understand the benefits and importance of localized data and code scope.
Const
7. What does the const keyword mean?
As soon as I hear the subject say, "const means constant", I know that I am dealing with an amateur. Last year Dan
Saks has fully summarized all usage of const in his article, So ESP (TRANSLATOR: Embedded Systems
Programming) every reader should be very familiar with what const can do and cannot do. If you have never read that article, just say that const means "read-only ".
. Although this is not a complete answer, I accept it as a correct answer. (If you want to know more detailed answers, read the Saks Article carefully .)
If the examinee can answer this question correctly, I will ask him an additional question:
What does the following statement mean?
Const int;
Int const;
Const int *;
Int * const;
Int const * a const;
/******/
The first two functions are the same. A is a constant integer. Third, it means that a is a pointer to a constant INTEGER (that is, an integer cannot be modified, but a pointer can be ). The fourth meaning is "".
A constant pointer to an integer (that is, the pointer to an integer 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 pointer refers
An integer cannot be modified, and a pointer cannot be modified ). If the examinee can answer these questions correctly, he will leave a good impression on me. By the way, you may ask, even if you do not
With the keyword const, it is still easy to write a program with the correct function. Why do I need to pay attention to the keyword const so much? I also have the following reasons:
& #8226 ;;
The key word const is used to send very useful information to the reader of your code. In fact, it declares a parameter as a constant to tell the user the purpose of applying this parameter. If you have spent a lot of time cleaning up
You will soon learn to thank this excess information for the garbage left by others. (Of course, programmers who know how to use const seldom leave garbage for others to clean up .)
& #8226; by attaching information to the optimizer, using the keyword const may produce more compact code.
& #8226; the rational use of the keyword const can enable the compiler to naturally protect parameters that do not want to be changed and prevent them from being accidentally modified by code. In short, this can reduce the occurrence of bugs.
Volatile
8. What does the keyword volatile mean? Three different examples are provided.
A variable defined as volatile means that this variable may be unexpectedly changed, so that the compiler will not assume the value of this variable. Precisely, the optimizer must carefully re-read the value of this variable every time when using this variable, rather than using the backup stored in the register. The following are examples of volatile variables:
& #8226; hardware registers of parallel devices (for example, Status Registers)
& #8226; a non-automatic variable (non-automatic variables) that will be accessed in the interrupt service Subprogram)
& #8226; variables shared by several tasks in multi-threaded applications
People who cannot answer this question will not be hired. I think this is the most basic problem to distinguish between C programmers and embedded system programmers. Embedded people often deal with hardware, interruptions, RTOS, etc. All of these require volatile variables. If you do not know volatile content, it will lead to disasters.
If the subject correctly answers this question (well, I suspect it will be the case), I will go a little deeper to see if this guy understands the full importance of volatile.
& #8226; can a parameter be const or volatile? Explain why.
& #8226; can a pointer be volatile? Explain why.
& #8226; what are the following function errors:
Int square (volatile int * PTR)
{
Return * PTR ** PTR;
}
The answer is as follows:
& #8226; yes. One example is read-only status registers. It is volatile because it may be unexpectedly changed. It is const because the program should not try to modify it.
& #8226; yes. Although this is not very common. One example is when a service subroutine repairs a pointer to a buffer.
& #8226; this code is a little abnormal. The purpose of this Code is to return the pointer * PTR points to the square of the value. However, since * 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;
}
* The value of * PTR may be unexpectedly changed, so a and B may be different. As a result, this Code may not return the expected square value! The correct code is as follows:
Long square (volatile int * PTR)
{
Int;
A = * PTR;
Return a *;
}
Bit manipulation)
9. In an embedded system, you must 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 one clears bit 3 of. In the preceding two operations, you must keep the other bits unchanged.
There are three basic responses to this problem.
& #8226; do not know how to start. The quilt has never worked on any embedded system.
& #8226; use bit fields. Bit
Fields is thrown to the dead corner of the C language. It ensures that your Code cannot be transplanted between different compilers, and that your Code cannot be reused. Unfortunately
Infineon is a driver written for its more complex communication chip. It uses bit fields, so it is completely useless to me, because my compiler implements bit in other ways.
Fields. Morality: Never let a non-embedded guy stick the actual hardware edge.
& #8226; Use # defines and bit masks. This is a highly portable method and should be used. The best solution is as follows:
# Define bit3 (0x1 <3)
Static int;
Void set_bit3 (void ){
A | = bit3;
}
Void clear_bit3 (void ){
A & = ~ Bit3;
}
Some people like to define a mask to set and clear values and define some descriptive constants at the same time, which is acceptable. I want to see several key points: constant, | = and & = ~ Operation.
Accessing fixed memory locations)
10. embedded systems often require programmers to access a specific memory location. In a project, the value of an integer variable whose absolute address is 0x67a9 must be set to 0xaa66. The compiler is a pure ANSI compiler. Write code to complete this task.
Test whether you know that it is legal to forcibly convert an integer number (typecast) into a pointer to access an absolute address. The implementation of this problem varies with the individual style. The typical code is as follows:
Int * PTR;
PTR = (int *) 0x67a9;
* PTR = 0xaa55;
A more obscure approach is:
A relatively obscure method is:
* (Int * const) (0x67a9) = 0xaa55;
Even if your taste is closer to the second option, I suggest you use the first option during the interview.
Interrupts)
11. interruption is an important part of embedded systems, which causes many compilation developers to provide an extension to interrupt Standard C support. The fact is that a new keyword is generated.
_ Interrupt. The following code uses the _ interrupt keyword to define an interrupt service subroutine (ISR). Please comment on this code.
_ Interrupt double compute_area (double radius)
{
Double area = pI * radius;
Printf ("/narea = % F", area );
Return area;
}
There are too many errors in this function, so people don't know where to start:
& #8226; ISR cannot return a value. If you do not understand this, you will not be hired.
& #8226; ISR parameters cannot be passed. If you do not see this, your chances of being hired are equivalent to the first.
& #8226; In many processors/compilers, floating points are generally not reentrant. Some processors/compilers need to import the registers at the amount into the stack. Some processors/compilers do not allow floating-point operations in ISR. In addition, ISR should be short and efficient, and it is unwise to perform floating point operations in ISR.
& #8226; with the 3.1 pulse, printf () often has re-import and performance problems. If you lose the third and fourth points, I won't be too embarrassed. Needless to say, if you can get the last two points, your prospects for employment will become brighter.
*****
Code example)
12. What is the output of the following code? Why?
Void Foo (void)
{
Unsigned int A = 6;
Int B =-20;
(A + B> 6 )? Puts ("> 6"): puts ("<= 6 ");
}
This problem tests whether you understand the principle of automatic Integer Conversion in the C language. I found that some developers know very little about these things. In any case, the answer to this unsigned integer question is:
"> 6 ". The reason is that when there are signed and unsigned types in the expression, all operands are automatically converted to the unsigned type. Therefore,-20 is a very large positive integer, so this expression
The calculated result is greater than 6. This is very important for embedded systems that should frequently use the unsigned data type. If you fail to answer this question, you will not be able to get the job.
13. Evaluate the following code snippet:
Unsigned int zero = 0;
Unsigned int compzero = 0 xFFFF;
/* 1's complement of zero */
For a 16-bit processor of the int type, the above Code is incorrect. It should be written as follows:
Unsigned int compzero = ~ 0;
This question reveals whether the examinee understands the importance of the processor font length. In my experience, good embedded programmers can understand hardware details and its limitations very accurately. However, PC programs often treat hardware as an unavoidable headache.
At this stage, the examinee is either totally frustrated or confident. If it is clear that the candidate is not good, the test will end here. However, if the subject does not do
Wrong, then I threw out the following append questions. These questions are difficult. I think only very good candidates can do well. To raise these questions, I hope to see more ways for the examinee to cope with the problems, instead
Answer. In any case, you should be entertaining...
Dynamic Memory Allocation (dynamic memory allocation)
14. Although not as common as embedded computers, embedded systems still have the process of dynamically allocating memory from heap. In the embedded system, what are the possible problems with dynamic memory allocation?
Here, I expect the examinee to mention memory fragmentation, fragment collection issues, variable holding time, and so on. This topic has been widely discussed in the ESP magazine (mainly p.j.
Plauger,
His explanation is far more than anything I can mention here.) Let's look back at these magazines! After putting the examinee into a false sense of security, I came up with a small program:
What is the output of the following code snippet? Why?
Char * PTR;
If (PTR = (char *) malloc (0) =
Null)
Else
Puts ("got a null pointer ");
Puts ("got a valid Pointer ");
This is an interesting question. Recently, one of my colleagues inadvertently passed the 0 value to the malloc function. After obtaining a valid pointer, I came up with this question. This is the code above,
The output of this code is "got a valid
Pointer ". I used this to discuss such a problem and see if the subject thought of the library routine. It is important to get the correct answer, but the solution to the problem is the basis for your decision.
This principle is more important.
Typedef
:
15 typedef is frequently used in C to declare an existing data type. You can also use a pre-processor to do similar things. For example, consider the following example:
# Define DPS struct s *
Typedef struct s * TPS;
The intention of the above two cases is to define the DPS and TPS as a pointing structure s pointer. Which method is better? (If so) Why?
This is a very subtle question. Anyone should be congratulated on answering this question (the legitimate reason. The answer is: typedef is better. Consider the following example:
DPS P1, P2;
TPS P3, P4;
The first extension is
Struct s * P1, P2;
.
The code above defines P1 as a point to the structure, and P2 as an actual structure, which may not be what you want. The second example correctly defines the P3 and P4 pointers.
Obscure syntax
16. The C language agrees to some shocking structures. Is the following structure legal? If so, what does it do?
Int A = 5, B = 7, C;
C = A ++ B;
This question will end happily in this quiz. Whether you believe it or not, the above example is completely syntactic. The problem is how does the compiler handle it? The authors of low-level compilation will actually argue about this issue. According to the best processing principle, the compiler should be able to handle as many valid usage as possible. Therefore, the above Code is processed:
C = A ++ B;
Therefore, a = 6, B = 7, c = 12 after the code is executed.
If you know the answer or guess the correct answer, you can do well. If you do not know the answer, I will not regard it as a question. I found that the biggest advantage of this problem is that it is a good topic about the code writing style, code readability, and code modifyability.
Okay, guys. You have finished all the tests now. This is my C language test question. I wrote it with pleasure. I hope you can read it in the same mood. If you think this is a good test, try to use it in your job search process. The Sky knows that maybe after a year or two, I will not do my current job. I also need to find one.
Nikel Jones is a consultant and now lives in Maryland. When he is not underwater, you can find him in multiple scope embedded projects. He is very happy to receive a letter from the reader, his e-mail address is: NAJones@compuserve.com
.