Have you ever encountered problems with function return classes in embedded programming?
[Copy link]
I don't know since when, I have a subconscious understanding of the function return value: "0" means success, non-"0" means failure.
Let me tell you a story first, which is a small episode during the project transplantation -
recently, I used a new chip for development. During the transplantation process, the official function library interface needs to be called, and the interface has a return value of uint32_t type. According to the manual, the function return value "0" means success, and "-1" means failure. The return value here is relatively simple, there are only two types: success and failure, and it is generally judged by "if (! ret) {success} else {failure}". In this way, during the transplantation process, most of the interface return values of the chip function library are these two types. When processing the results, I just copy and paste "if (! ret) {success} else {failure}".
An accident occurred. When I called the "comparison" function interface of the library, the result was always wrong, and the return value was always "1", which is the "true" logic, so the upper interface kept reporting errors to the user at the application layer. I checked the input parameters of the interface by looking through the manual. I suspected that the data processed by other interfaces was wrong. I also checked other called interfaces before this interface. However, the return value description of this interface in the manual was placed on the next page due to typesetting. You could never imagine that the return value of the function here was "1" for success and "0" for failure!
Looking back, it took me almost a whole afternoon to check the entire execution process. I never expected that I would ignore this detail. It was really "no effort to find it after searching everywhere"!
In short, the return value design of the function library interface provided by the chip manufacturer is too simple and has not reached a complete unified standard. In the final analysis, I can only blame myself for not paying attention to such an important detail. As a developer, you should look for reasons from yourself and ensure that there are no exceptions in every link of your own. Even if you are faced with a difficult code, you can handle it with ease.
The lesson for me can only be not to ignore details. But sometimes, why not do things that can be done well in one go! The definition of the function return value can actually be relatively standardized. Unifying it will be helpful to both myself and others.
There are two types of return values: one is the data obtained after the function is executed, and the other is the status result after the function is executed.
The return data is the result obtained after a certain operation is performed on the input parameters; the return status result mainly indicates whether the function is executed correctly.
Return data, this return value cannot indicate whether it is executed correctly. It can only be considered that if there is a return value, it is executed correctly. Therefore, when such a function is executed, there should be no parameter correctness judgment, and it should be executed regardless of what kind of parameters are passed.
The simplest example is a summation function:
uint16_t func_sum (uint8_t val1, uint8_tval2)
{
Return (val1+val2);
}
Such a return value is the data result obtained after the function is executed. There is no need to discuss this too much.
Return status results, such as the official library interface of the chip mentioned above, use "0" and "-1" to indicate the results of success or failure after execution.
In the article "Embedded Hardware Communication Interface - Using RingBuffer to Process Data (II) Detailed Design Process", the "Read One Byte", "Read Multiple Bytes" and other subsequent functions return success and failure status after execution. These statuses are members of the rb_ret_t enumeration type.
For example, when writing a multi-byte interface, if the execution fails, it may be due to parameter errors or insufficient space. At this time, it is very necessary to return different status results for different errors. Therefore, the return code is no longer "0" and "-1", but other values of zero and non-zero.
How to design the return status also has its own requirements. If you give the return status code because of a momentary impulse, close your eyes and stamp your feet, and the status result definitions of the interfaces of the same layer and the same type are not consistent, then it is too casual. If such interfaces are encapsulated without explaining the interfaces one by one, you may deceive yourself and others one day.
The definition of the return status result can be designed as:
true and false of Boolean type (bool);
various status codes of enumeration type;
Boolean type, used in C++, has only two states, true and false. If used in C-based embedded development, it needs to be redefined.
Similar to the three enumeration definitions in the STM32 V3.5.0 standard library, each enumeration only defines two states, which can also be called Boolean type.
When designing your own system, you can also use this enumeration to define the status result returned by the function.
However, in the enumeration here, the member value "0" indicates failure, and non-"0" indicates success. In this way, there is only one failure, which is also a problem for subsequent application expansion. For example, how to reflect different return status results for different reasons for failure, so consider introducing various status codes of enumeration types.
"0" indicates success, and non-"0" indicates failure. This thinking also conforms to the logical characteristics of computers that "0" is false and non-"0" is true. When the program is executed, success is success, and there is no need to consider why the execution is successful. However, when it fails, there are always problems that lead to failure. At this time, it is necessary to analyze the failure. There are many reasons for failure. For computers, there are also many logical "true". 1, 2, 3, ..., 99, ..., N, as long as it is not "0", it is a logical "true" of non-"0".
The various status codes of enumeration types are mainly used to solve the problem of returning error codes when different failure reasons occur. This can facilitate the upper-level application to check the parameters, try to adjust the parameters and call the interface again to execute again; or the error codes are processed separately and displayed in the user interaction interface to prompt the user to return the status when executing a certain function.
It can be seen that in C development, the return value of the same enumeration type, why not expand the members of the enumeration to represent complex and diverse execution results.
At the same time, when writing a function, the return type of the function is defined by the enumeration type. For development, by viewing the member table in the enumeration type, you can quickly know what state the execution result of the function may have, at least there is an expected judgment.
In this way, the corresponding return type can be designed for each module and each layer of the encapsulated function.
In summary, these are just the daily programming habits of developers, or the specifications of interface design. The type definition of the return value is not absolutely right or wrong. Right or wrong is only determined by the basis for judgment when the program is executed. However, a good coding specification and a unified comparison table are very critical to the maintenance and iteration of the code!
|