Professor Zhou Ligong’s hard work over several years resulted in two books: **"Programming and Data Structures"** and **"Programming for AMetal Framework and Interface (I)"**. Following the release of these books, there was a significant surge in interest within the electronics industry. With Professor Zhou's permission, this public account has been serializing the content of the book **"Programming and Data Structures"** and is eager to share it.
The second chapter focuses on programming techniques, specifically covering section 2.1.1 on function pointers and 2.1.2 on pointer functions.
>> >> >> > 2.1 Function Pointers and Pointer Functions
>> >> > 2.1.1 Function Pointers
A pointer to a variable points to a piece of data, while a pointer to another variable accesses different data. Similarly, compiled functions are pieces of code, and the system allocates storage space for these codes. The starting address (or entry address) of the code is essentially a pointer to the function, meaning execution jumps to a specific address and runs the corresponding code. A function pointer points to a piece of code (a function) and can point to different functions, thus enabling different behaviors.
Since a function name is a constant address, you can call the corresponding function by assigning the function’s address to a function pointer. Similar to arrays, the function name itself returns the address of the function. When a function name appears in an expression, the compiler automatically converts it to a pointer. This behavior is akin to how an array variable name fetches its address implicitly. Thus, the function name directly corresponds to the memory address of the function's instruction code, allowing the function name to be directly assigned to a function pointer. Since the value of a function pointer can change, the same pointer can point to different functions. Consider the following definition:
```c
int (*pf)(int); // What is the type of the function pointer pf?
```
K&R, the creators of the C language, explained this by stating: “Because * is a prefix operator, its precedence is lower than (). To ensure proper parsing, parentheses are needed.†This explanation is somewhat convoluted and tends to confuse people. In reality, * and () in declarations are not operators, and their precedence is defined elsewhere in the grammar rules. Here’s a breakdown:
```c
int (*pf)(int a); // pf is a pointer to a function returning int (parameter is int)
```
That is, `pf` is a pointer to a function that returns an integer and accepts an integer argument. The type `int (*)(int)` is interpreted as a pointer to a function that returns an integer (with a parameter of type int). Adding a `typedef` before the definition simplifies things:
```c
typedef int (*PF)(int a);
```
Before the typedef, `pf` is a function pointer variable; after the typedef, `pf` becomes a type for function pointers. It’s common practice to name this type `PF`. For example:
```c
typedef int (*PF)(int a);
```
Unlike other types of declarations, declaring a function pointer requires the use of the `typedef` keyword. Additionally, the only difference between a function pointer declaration and a function prototype is that the function name is replaced by `(*PF)`, where `*` signifies “a pointer to a function of type PFâ€. Clearly, function pointer variables like `pf1` and `pf2` can be defined using the `PF` type:
```c
PF pf1, pf2;
```
While this is equivalent to:
```c
int (*pf1)(int a);
int (*pf2)(int a);
```
This type of writing is harder to understand. Since a function pointer variable is just a variable, its value can change, allowing the same pointer to point to different functions. To use function pointers effectively:
- Obtain the address of the function, e.g., `pf = add`, `pf = sub`.
- Declare a function pointer, e.g., `int (*pf)(int, int);`.
- Use the function pointer to call functions, such as `pf(5, 8)` or `(*pf)(5, 8)`.
Why is `pf` equivalent to `(*pf)`?
One argument is that since `pf` is a function pointer, assuming it points to the `add()` function, `*pf` refers to the `add` function, so calling it with `(*pf)()` makes sense. Although this format looks awkward, it provides a strong hint—code is invoking a function using a function pointer.
Another perspective is that since the function name is a pointer to a function, the pointer to the function should behave similarly to the function name. Therefore, using `pf()` to call the function is simpler and more elegant, making it a preferred approach. While these explanations might seem contradictory, different contexts offer different insights, and tolerating logical ambiguities is a hallmark of human thought processes.
In a pocket calculator, various operations such as addition, subtraction, multiplication, and division are frequently required. Although the calling method remains consistent, during execution, it is necessary to decide which function to call based on the specific scenario. If the direct invocation method shown in Figure 2.1(a) is used, it inevitably creates a dependency structure. Any changes in the details will affect the strategy. By contrast, using the function pointer interface as shown in Figure 2.1(b), the dependency structure is inverted. Here, the details and strategies depend on the function pointer interface, breaking unwanted direct dependencies.
When the abstraction of direct access is inverted into a function pointer, the high-level module no longer depends on the low-level module. Instead, high-level modules rely on abstraction—a function pointer interface—while the details depend on abstraction. Both `pf()` implementations rely on the function pointer interface. In C, function pointers are typically used to implement Dependency Inversion Principle (DIP) and break unwanted direct dependencies. Services can be invoked via function pointers (called code), and services can also call back user functions through function pointers.

Figure 2.1 Inverting Dependencies Using Function Pointers
Function pointers are a powerful language feature often overlooked by programmers. They make code more flexible and measurable, while eliminating repetitive conditional logic. They also save the caller from having to compile or link a specific function, significantly reducing the coupling between C language modules. However, the use of function pointers is conditional. If the calling relationship between the calling function and the called function never changes, the direct calling method is the simplest. In such cases, the coupling between modules is reasonable, resulting in simple, straightforward code with minimal overhead. When a function needs to be called dynamically at runtime using one or more function pointers, function pointers are the best choice. Typically, this is referred to as a dynamic interface. The sample program is detailed in Listing 2.1.
Program Listing 2.1 Sample Program Calling Functions via Function Pointers (1)
```c
#include
int add(int a, int b)
{
printf("addition function\n");
return a + b;
}
int sub(int a, int b)
{
printf("subtraction function\n");
return a - b;
}
int main(void)
{
int (*pf)(int, int);
pf = add;
printf("addition result:%d\n", pf(5, 8));
pf = sub;
printf("subtraction result:%d\n", pf(8, 5));
return 0;
}
```
Since any data type pointer can be assigned to a `void` pointer variable, and the essence of a function pointer is an address, this feature allows us to define `pf` as a `void *` type pointer. Then, any pointer can be assigned to the `void *` type pointer variable. The calling method is as follows:
```c
void *pf = add;
printf("addition result:%d", ((int (*)(int, int)) pf)(5, 8));
```
During the use of function pointers, the value of the pointer indicates the address to which the program will jump, and the type of the pointer determines how the program is called. When calling a function with a function pointer, it is crucial to ensure that the type of the function being called matches the type of the function pointed to. Therefore, the `void *` type must be converted to `((int (*)(int, int)) pf)`, with the type being `int (*)(int, int)`.
>> >> >> > 2.1.2 Pointer Functions
In fact, pointer variables are extremely versatile. Not only can pointers serve as arguments to functions, but they can also be used as return values for functions. When the return value of a function is a pointer, the function is referred to as a pointer function. Given a pointer to two integers, the function in Listing 2.2 returns a pointer to the larger of the two integers. When `max` is called, a pointer to two `int` type variables is used as a parameter, and the result is stored in a pointer variable. The pointer returned by the `max` function is one of the two pointers passed in as arguments.
Program List 2.2 Find the Maximum Function (Pointer as Return Value)
```c
#include
int *max(int *p1, int *p2)
{
if (*p1 > *p2)
return p1;
else
return p2;
}
int main(int argc, char *argv[])
{
int *p, a, b;
a = 1; b = 2;
p = max(&a, &b);
printf("%d\n", *p);
return 0;
}
```
Of course, the function can also return a string, which is essentially the address of the string, but it’s important to ensure that a valid address is returned. You can either return the address of a static string or allocate a string on the heap and return its address. Be cautious about returning the address of a local string, as memory may be overwritten by other stack frames.
Let’s examine the difference between a pointer function and a function pointer variable. If the following definitions are made:
```c
int *pf(int *, int); // int *(int *, int) type
int (*pf)(int, int); // int (*)(int, int) type
```
Although there is only one set of parentheses between the two, their meanings are quite different. The essence of a function pointer variable is a pointer variable that points to a function. On the other hand, the essence of a pointer function is a function that declares `pf` as taking two arguments: one is `int *` and the other is `int`. The return value is a pointer of type `int`.
In pointer functions, there is a category of functions whose return value is a pointer to a function. For beginners, even writing such a function statement is challenging, and seeing such syntax can be confusing. For example:
```c
int (* Ff(int))(int, int); // Ff is a function
int (* ff(int))(int, int); // Ff is a pointer function whose return value is a pointer
int (* ff(int))(int, int); // The pointer points to a function
```
Such writing is extremely difficult to understand, leading some beginners to believe that writing incomprehensible code demonstrates their skill. In reality, the ability to write clear, understandable code is a measure of a skilled programmer. Using `typedef`, `PF` becomes a function pointer type:
```c
typedef int (*PF)(int, int);
```
With this type, the declaration of the aforementioned function becomes much simpler:
```c
PF ff(int);
```
The following uses Program Listing 2.3 as an example to illustrate the use of function pointers as function return values. When the user inputs `d`, `x`, and `p`, the maximum, minimum, and average values of the array are obtained.
Listing 2.3 Sample Program Finding Best Values and Averages
```c
#include
#include
double getMin(double *dbData, int iSize) // Find the minimum
{
double dbMin;
assert((dbData != NULL) && (iSize > 0));
dbMin = dbData[0];
for (int i = 1; i < iSize; i++){
if (dbMin > dbData[i]){
dbMin = dbData[i];
}
}
return dbMin;
}
double getMax(double *dbData, int iSize) // Find the maximum
{
double dbMax;
assert((dbData != NULL) && (iSize > 0));
dbMax = dbData[0];
for (int i = 1; i < iSize; i++){
if (dbMax < dbData[i]){
dbMax = dbData[i];
}
}
return dbMax;
}
double getAverage(double *dbData, int iSize) // Calculate the average
{
double dbSum = 0;
assert((dbData != NULL) && (iSize > 0));
for (int i = 0; i < iSize; i++){
dbSum += dbData[i];
}
return dbSum / iSize;
}
double unKnown(double *dbData, int iSize) // Unknown algorithm
{
return 0;
}
typedef double (*PF)(double *dbData, int iSize); // Define function pointer type
PF getOperation(char c) // Get the operation pointer based on the character, return the function pointer
{
switch (c){
case 'd':
return getMax;
case 'x':
return getMin;
case 'p':
return getAverage;
default:
return unKnown;
}
}
int main(void)
{
double dbData[] = {3.1415926, 1.4142, -0.5, 999, -313, 365};
int iSize = sizeof(dbData) / sizeof(dbData[0]);
char c;
printf("Please input the Operation :\n");
c = getchar();
PF pf = getOperation(c);
printf("result is %lf\n", pf(dbData, iSize));
return 0;
}
```
The first four functions implement the maximum, minimum, average, and unknown algorithms. The return value obtained by `getOperation()` based on the input character is returned in the form of a function pointer. From `pf(dbData, iSize)`, it can be seen that the function is called through this pointer. Note that a pointer function can return a new memory address, the address of a global variable, or the address of a static variable, but cannot return the address of a local variable, as after the function ends, the memory allocated for the local variable is automatically released. Clearly, accessing the data pointed to by this pointer in the calling function will yield unpredictable results.
If you wish to learn more about embedded courses, please scan the QR code below and start learning today!
4G Outdoor CPE
Can you boost your WiFi signal with outdoor 4G CPE?
When you travel or go to some remote areas, you may be annoyed by poor reception. Is there any way to get a strong WiFi router signal outdoors in a 4G LTE network? Very good, outdoor 4G CPE router would be a good choice!
What is an outdoor 4G CPE router?
An outdoor 4G CPE router differs from a Wifi-only router in that it needs to be connected to a fiber optic network. The 4G CPE WiFi router can pick up the carrier's 4G LTE network signal and convert it into broadband and Wi-Fi. Just plug in your SIM card with your data plan and enjoy a stable and reliable WiFi signal with family and friends. This Outdoor CPE can be used in harsh environments. If you install your router outside or near a window in an area with a weak 4G signal, your device can receive a better 4G signal.
Second, what are the characteristics of outdoor 4G CPE router?
1. Better network for ODU and IDU
4G CPE outdoor routers include an outdoor unit (ODU) and an indoor unit (IDU). Help your device receive the best outdoor cellular signal through the ODU, and connect to the indoor WiFi router through the network cable to experience better network speed. As shown in the figure below, an outdoor LTE CPE (ODU) is installed outdoors and connected to an indoor Wi-Fi router (IDU) via a network cable. The entire 4G device is powered by POE. This data will be transmitted over the same Ethernet cable, eliminating the need to connect the ODU to a power outlet.
2. High-speed multi-user available
The outdoor 4G CPE features a built-in 4G LTE modem and a 5dBi high-gain antenna. LTE CAT4, download speeds up to 150Mbps, WiFi speeds up to 300Mbps, can connect 32 users at the same time. The high-gain antenna of the outdoor 4G CPE router enables it to have higher power and stronger signal transmission and reception capabilities than mobile phones. Therefore, the CPE router can receive the signal. If your phone can't receive a signal in some areas. Sometimes you also use your phone as a hotspot to share Internet access with your friends, right? Similarly, this 4G LTE CPE router allows 32 users to connect to WiFi at the same time, allowing more users to connect and receive a better signal than a phone sharing hotspot. In addition, the IDU has four Lan ports and can be connected to the device through network cables, which is also a backup mode of the Internet.
3. Excellent outdoor performance and design
On the one hand, outdoor LTE CPE is waterproof, UV resistant and corrosion resistant. It can be used at -20℃~60℃ operating temperature. Therefore, it is ideal for outdoor deployment. On the other hand, there are a variety of installation methods. CPE can be mounted on Windows or walls by mounting brackets. It is also possible to attach it to the antenna mast. In addition, the signal strength is displayed through the LED indicator to facilitate users to find the best location to get a better 4G signal.
4. Support different frequency bands
Outdoor 4G CPE supports a variety of frequency bands, including LTE-FDD, LTE-TDD, 3G WCDMA, and 2G GSM network bands. Meet the needs of different frequency bands in different regions and make full use of network resources.
5. Convenient management of CPE
Start the Web browser to log in to the Web management page. You can configure and manage the CPE easily. The web management system supports Linux. Provides functions such as WebUI management, Telnet, SSH terminal system status monitoring, NTP client, synchronization between devices and the system clock network, and configuration file import and export.
6. Applicable to various application scenarios
CPE is designed to provide ISP or operator with 4G LTE outdoor wifi router to facilitate network connection, whether at home, or in enterprises and remote areas, to bring users a wonderful network experience.
All in all, an outdoor 4G CPE router is an excellent choice for connecting to the Internet in remote areas and places where the signal is weak, the wired network is unreliable, or there is a lack of reliable WiFi. It's worth deploying outdoor CPE in rural, coastal, boat, caravan, campsite and remote areas to enjoy the best network speeds and outdoor activities! It can even reduce complex cabling deployments for home networks without the need to install a wired fiber network.
4G Outdoor Cpe,4G Lte Outdoor Cpe Router,4G Lte Outdoor Cpe,Outdoor 4G Lte Cpe Router
Shenzhen MovingComm Technology Co., Ltd. , https://www.movingcommtech.com