1. 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:
(1) Hardware registers of parallel devices (for example, Status Registers)
(2) Non-automatic variables that will be accessed in an interrupt service subroutine)
(3) 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.
- Can a parameter be const or volatile? Explain why.
A: 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.
- Can a pointer be volatile? Explain why.
A: Yes. Although this is not very common. One example is when an interrupt service subroutine repairs a pointer to a buffer.
- What are the following function errors:
Int square (volatile int * PTR)
{
Return * PTR ** PTR;
}
A: This code is 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 *;
}
2. 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;
3. If both the number of signed characters and the number of unsigned characters exist in the expression, the number of signed characters will be increased to the number of unsigned characters.
Get array Length
Template <typename T, size_t n>
Size_t arrarysize (T (& array) [N]) {return N ;}
4. Understanding of array pointers and multi-dimensional arrays
| |
General Form |
Typedef Definition |
Pointer Array |
Int * A [10]; |
Typedef int * t;
T a [10]; |
Array pointer |
INT (* A) [10]; |
Typedef int T [10];
T *; |
For example:
(1) int A [10];
INT (* pA) [10] = &;
A is an array. In the & A expression, the array name is left and the first address of the entire array is assigned to the pointer Pa. Note: & A [0] indicates the first address of the first element of array A, and & A indicates the first address of array A. Obviously, these two addresses have the same value, however, the two expressions have two different pointer types, the former is int *, and the latter is int (*) [10]. * PA indicates the array a pointed to by PA. Therefore, the expression (* pA) [0] can be used to obtain the [0] element of the array. Note that * pA can be written as PA [0], so (* pA) [0] can also be rewritten as PA [0] [0], pa is like the name of a two-dimensional array. What does it mean? Next we will put Pa and two-dimensional arrays together for analysis.
(2) int A [5] [10];
INT (* pA) [10] = & A [0];
Then Pa [0] And a [0] Take the same element. The only thing that is more complex than the original one is that this element is an array consisting of 10 int, rather than the basic type. In this way, we can use Pa as a two-dimensional array name. Pa [1] [2] and a [1] [2] Take the same element, in addition, PA is more flexible than a. array names do not support assignment, auto-increment, and pointers, pa ++ skips a row of a two-dimensional array (40 bytes) and points to the first address of a [1.
(3) int A [2] [3] [5];
INT (* pA) [5] = A [0];
Int * PPA = A [0] [0];
A Indicates a + 0, which is a pointer to the first two-dimensional array,
A [0] indicates a [0] + 0, which is a pointer to the first one-dimensional array.
A [0] [0] indicates a [0] [0] + 0. It is a pointer to the first element of a one-dimensional array.
A [0] [0] [0] indicates an int, which is the first element of a one-dimensional array.
5. Understanding of polymorphism in C ++
The implementation of polymorphism in C ++ requires that the corresponding functions of the base class be defined as virtual.
It can be understood as follows: we need to override some methods of the base class using subclass methods. To achieve this goal, the first step is that the prototype of the function between the subclass and the base class is the same. The second step is to declare the method in the base class as virtual. This is actually to inform the compiler that I want to implement polymorphism for this function. When generating the virtual function table (V-table) of the subclass, pay attention to it, replace (overwrite) the address of the base class function with the address of the subclass function.
7. C language considerations
(1) return values of scanf and printf
The Return Value of the scanf () function is the number of reads in the required format. If the read error is (that is, no reading is successful), 0 is returned. If an error is encountered, EOF is returned;
The Return Value of the printf () function is the number of outputs. The return value is an integer.
(2) usage of sizeof which is easy to be ignored
Sizeof returns the length of a String constant.
For example, sizeof ("AB") = 3
Char s [] = "ABC"; sizeof (S) = 4
The following information is found on the Internet:
For char STR [] = "abcdef"; there is sizeof (STR) = 7, because the STR type is Char [7],
Sizeof ("abcdef") = 7, because the type of "abcdef" isConst char [7].
For char * PTR = "abcdef"; there is sizeof (PTR) = 4, because the PTR type is char *.
For char str2 [10] = "abcdef"; there is sizeof (str2) = 10, because the str2 type is Char [10].
For void func (char SA [100], int Ia [20], char * P );
Sizeof (SA) = sizeof (IA) = sizeof (p) = 4, because the SA type is char *, and the IA type is int *, the p type is char *.
(3) how to determine whether a file exists in C
Use Function access. The header file is Io. H. prototype:
Int access (const char * filename, int amode );
If the amode parameter is 0, the object existence is checked. If the object exists, 0 is returned. If the object does not exist,-1 is returned.
This function can also check other file attributes:
06 check read/write permissions
04 check read permission
02 check write permission
01 check the execution permission
00 check file existence
The experiment is successful under UNIX and VC.
The advantage is: fopen (..., "R") is not good. It cannot work when there is no read permission. Even if the file does not have the read permission, you can determine whether the file exists or not: 0 is returned, and-1 is not returned.
# Include <stdio. h>
Int main ()
{
Printf ("% d", access ("111", 0 ));
}
Create a directory system ("mkdir D: \ ABC \ Def") in C ");
8. Functions of extern C in C ++
Because C language and C ++ have different compilation rules, we need to tell the system which functions are compiled in C mode and which functions need to be compiled in C ++ mode. If you do not add extern "C", the system will prompt that this function cannot be found during compilation.
Extern "C" indicates that the internal Symbol names generated by Compilation Use the c Convention.
Example: int fun (int I, Int J)
C: _ fun
C ++: _ fun_int_int
The specific generation may be related to the compiler. C ++ supports overloading, And the overloading is determined during the compilation period. Therefore, C ++ must differentiate the overloaded functions based on the internal Symbol names, so the parameter type is added after the function name.
9. Why is a template class used in C ++.
A: (1) create a Data Structure with dynamic growth and reduction
(2) It is type-independent and therefore highly reusable.
(3) It checks the data type during compilation instead of runtime, ensuring the type security.
(4) It is platform-independent and portable.
(5) can be used for basic data types
10. Near-heap and Remote Heap problems in C ++
It should be a problem with the near and far pointers.
The reason is: if the dynamically created data volume is large, a data segment (usually 64 K, the pointer remains unchanged during this time period, and the offset pointer changes within 16 bits) cannot be placed, A new data segment is required to store more data. The original heap part is called NEAR heap, And the heap part of the new data segment after the segment address is changed is called the remote heap
The memory address obtained by the PC is composed of a segment address and an offset address. Each segment cannot exceed 64 K Bytes. Therefore, the address access within each segment can be achieved through the offset address, because the segment address in the segment address register remains unchanged. When a pointer is used, only 16 is enough. This class is the near pointer. To retrieve data in another segment, you must span the segment. You must specify the segment address and offset address of the access segment. During this period, the segment address in the address register must be changed, when you use a pointer to point to an address in another segment, it will be represented by 32 bits, that is, the far pointer.
Because DOS is a 16-bit operating system, the program code is limited by segment. The near pointer can only point to code or data within 64 KB. Far supports cross-segment addressing. If I remember correctly, there seems to be a far pointer of the huge type. However, because Watcom, djgpp, and other dos compilers, and all windows compilers are 32-bit, there is no 64 K limit, and pointers are not far away.