Synchronizing Declarations and Definitions of static Functions

Some organizations have interior standard for formatting source codes in the C programming language. In particular, we also have requirements for the code.

I already had the text Synchronization of the order of declarations and definitions of global functions. However, a similar story is also relevant for static functions. Among 463x We have internal code style rules and such mandatory code formatting requirement:

The sequence of static function declarations must match the sequence of static function definitions at the end of the *.c file.

I think it's clear to everyone that if static C functions were defined at the beginning of a C file, this desperate rule would not exist at all. But this is not the place for you! We also have another mandatory rule

All static functions must be defined at the very bottom of the *.c file.

In this regard, in order for the code to be compiled at all, it is now necessary to artificially re-declare the prototypes of these same static functions at the beginning of the *.c file. Isn't that normal? And if so, then let the order match. A circus with horses, and nothing more.

This is a prime example of how, literally out of thin air, you can create spokes in the wheels of yourself and your colleagues for many, many years to come. This is a classic example of IT drill that is not justified in any way.

It is clear that the behavior of the code will be one and the samethat static prototypes are sorted, that they are not sorted, it will not change the weather. The compiler does not care. Unit tests (if any) will pass the same way in any case.

You might think that we have nothing better to do here than shuffle function definitions around, tie some bows on them, instead of real work.

We don't have a single unit test. We compile the code in an Arduino-like IDE, we don't have UART-CLI. But we do make sure that the order of static function declarations matches the order of static function definitions at the end of the *.c file. How is that?

How do they say: “One zero in favor of Biden”?

However, there is such a rule here, and in order for commits with code to pass the censorship on Gerrit and end up in the common fund, no matter how you look at it, this requirement must be met.

What's the problem?

The problem is also that the intellectual employee who dreamed up all these rules was too lazy to scribble down utilities for automatic control of all this lawmaking. Probably, if supervisory utilities were developed, his ardor would quickly fade.

However, the rule mandatory and, no matter how you look at it, you have to live with it.

Any development begins only when full-fledged debugging tools appear.

It is obvious that manually tracking down these violations of the order of declarations and definitions is very tedious, routinely long and expensive. Therefore, programmers have long cherished the dream of the appearance of a magic wand: a console program that automatically finds these notorious violations of the order of static declarations.

And, as usual, such a utility in the public domain did not exist in nature until today, just as pure plutonium did not exist in the earth's crust before the appearance of the first man-made nuclear reactors.

That's why I wrote such a locator utility. I called it prototype_check with key csp. I will send the utility to all my fellow sufferers.

What software do you need?

#

Utility name

What is this utility for?

1

awk / gawk

csv string parser and processor

2

winmerge

Comparing text files

3

sed

deleting and replacing text in a file

4*

ctags

extractor of text tokens from sources in different programming languages

5

cmp

file comparison utility

What's the plan?

I propose to implement such a software conveyor. Only 4 stages. The scope of work is as follows:

Implementation

The core of this whole solution is an old utility ctags. ctags plays a major role here. Let's explain the options of the ctags utility that we will need in this solution here and now.

ctags option

Transcript

-x –c-types=f

extract only functions from *.c file

-x –c-kinds=p

extract function prototypes from *.c file

–sort=no

do not sort found tokens (functions) in the report

-fcTagReport.txt

save report to file сTagReport.txt

And now an explanation of the utility's algorithm. So, let's start from scratch…

Phase 1: Show all functions in *.c file

To show only the functions you need to write

ctags.exe  --sort=no -fcTagReport.txt -x --c-types=f i2c_drv.c

This raw log crystallized

Hidden text
I2C_Init         function    783 C:\projects\source\I2C\i2c_drv.c STD_RESULT I2C_Init(void)
I2C_DeInit       function    896 C:\projects\source\I2C\i2c_drv.c STD_RESULT I2C_DeInit(void)
I2C_StartReading function    968 C:\projects\source\I2C\i2c_drv.c STD_RESULT I2C_StartReading(const U8 nBus,
I2C_HighLevel_RX_ISR function   1758 C:\projects\source\I2C\i2c_drv.c void I2C_HighLevel_RX_ISR(const U8 nBus)
I2C_HighLevel_TX_ISR function   1775 C:\projects\source\I2C\i2c_drv.c void I2C_HighLevel_TX_ISR(const U8 nBus)
I2C_HighLevel_Error_ISR function   1932 C:\projects\source\I2C\i2c_drv.c void I2C_HighLevel_Error_ISR(const U8 nBus)
I2C_LL_GPIOInit  function   2048 C:\projects\source\I2C\i2c_drv.c static void I2C_LL_GPIOInit(const U8 nArgBus)
I2C_LL_GPIODeInit function   2144 C:\projects\source\I2C\i2c_drv.c static void I2C_LL_GPIODeInit(const U8 nArgBus)
I2C_SetConfigTransfer function   2246 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_SetConfigTransfer(const I2C_BUS nArgBus,
I2C_SendData     function   2417 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_SendData(const I2C_BUS nArgBus,
I2C_ReceiveData  function   2470 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_ReceiveData(const I2C_BUS nArgBus,
I2C_ResetCtrl2Register function   2527 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_ResetCtrl2Register(const I2C_BUS nArgBus)
I2C_ClearFlags   function   2593 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_ClearFlags(const I2C_BUS nArgBus,
I2C_CheckFlag    function   2661 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_CheckFlag(const U8 nBus,
I2C_SetInterruptState function   2728 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_SetInterruptState(const U8 nArgBus,
I2C_RefreshTxdtRegister function   2783 C:\projects\source\I2C\i2c_drv.c static void I2C_RefreshTxdtRegister(I2C_tag* const pArgHw)
I2C_ConversionCfgIndex function   2810 C:\projects\source\I2C\i2c_drv.c static STD_RESULT I2C_ConversionCfgIndex(const U8 nArgBus,

Phase 2: Remove all non-static lines

In the ctags report, you need to leave only static functions. Or you need to delete all the lines that do not contain keyword static. This can be done with the console utility sed

sed -i '/ static /!d' cTagReport.txt

Only the definitions of static functions remain. This is the log we get

Hidden text
I2C_LL_GPIOInit  function   2048 C:\projects\source\third_party\I2C\i2c_drv.c static void I2C_LL_GPIOInit(const U8 nArgBus)
I2C_LL_GPIODeInit function   2144 C:\projects\source\third_party\I2C\i2c_drv.c static void I2C_LL_GPIODeInit(const U8 nArgBus)
I2C_SetConfigTransfer function   2246 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_SetConfigTransfer(const I2C_BUS nArgBus,
I2C_SendData     function   2417 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_SendData(const I2C_BUS nArgBus,
I2C_ReceiveData  function   2470 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_ReceiveData(const I2C_BUS nArgBus,
I2C_ResetCtrl2Register function   2527 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_ResetCtrl2Register(const I2C_BUS nArgBus)
I2C_ClearFlags   function   2593 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_ClearFlags(const I2C_BUS nArgBus,
I2C_CheckFlag    function   2661 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_CheckFlag(const U8 nBus,
I2C_SetInterruptState function   2728 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_SetInterruptState(const U8 nArgBus,
I2C_RefreshTxdtRegister function   2783 C:\projects\source\third_party\I2C\i2c_drv.c static void I2C_RefreshTxdtRegister(I2C_tag* const pArgHw)
I2C_ConversionCfgIndex function   2810 C:\projects\source\third_party\I2C\i2c_drv.c static STD_RESULT I2C_ConversionCfgIndex(const U8 nArgBus,

Phase 3: Only the first column needs to be selected from the report

You can select columns from text files using the utility awk. With such a team.

gawk '{print $1}' cTagReport.txt > definitions.txt

Phase 4: Extract function prototypes

To extract only prototypes from src.c to cTagReport.txt, you need to run the following command

ctags --sort=no -fcTagReport.txt  -x --c-kinds=p src.c

You will get a file like this with a list of prototypes.

Hidden text
I2C_LL_GPIOInit  prototype   719 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static void I2C_LL_GPIOInit(const U8 nArgBus);
I2C_LL_GPIODeInit prototype   722 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static void I2C_LL_GPIODeInit(const U8 nArgBus);
I2C_SetConfigTransfer prototype   725 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_SetConfigTransfer(const I2C_BUS nArgBus,
I2C_SendData     prototype   730 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_SendData(const I2C_BUS nArgBus,
I2C_ReceiveData  prototype   734 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_ReceiveData(const I2C_BUS nArgBus,
I2C_ResetCtrl2Register prototype   738 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_ResetCtrl2Register(const I2C_BUS nArgBus);
I2C_ClearFlags   prototype   741 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_ClearFlags(const I2C_BUS nArgBus,
I2C_CheckFlag    prototype   745 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_CheckFlag(const U8 nBus,
I2C_SetInterruptState prototype   750 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_SetInterruptState(const U8 nArgBus,
I2C_RefreshTxdtRegister prototype   755 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static void I2C_RefreshTxdtRegister(I2C_tag* const pArgHw);
I2C_ConversionCfgIndex prototype   758 C:\projects\code_base_firmware\source\I2C\i2c_drv.c static STD_RESULT I2C_ConversionCfgIndex(const U8 nArgBus,

Phase 5: Extract only function names from the prototype report

Now you only need to select the function names. This is essentially the first column. Such tasks are solved by the cult utility awk

gawk '{print $1}' cTagReport.txt   > declarations.txt

Inside the text file declarations.txt, the list of functions has crystallized as it is presented in the part where the static function prototypes are declared.

Phase 6: Compare feature lists

At this stage, the task was reduced to a simple comparison of two text files. In theory, they should be identical, like two peas in a pod. You can compare text files with the utility cmp

cmp -s declarations.txt definitions.txt

The result of the comparison will show the anomalies.

Here is the full script that does the check

cls
echo off

set srcFile=some_driver.c
set cTagFile=cTagReport.txt
set StativRepDef=StativRepDef.txt
set StativRepDec=StativRepDec.txt

rm -f %cTagFile%
rm -f %StativRepDef%
rm -f %StativRepDec%

set options=--sort=no
set options=%options% -f%cTagFile%
set options=%options% -x --c-types=f
ctags.exe  %options% %srcFile%
sed -i '/ static /!d' %cTagFile% 
gawk '{print $1}' %cTagFile%  > %StativRepDef%
rm -f %cTagFile%

set options=--sort=no
set options=%options% -f%cTagFile%
set options=%options%  -x --c-kinds=p
ctags %options% %srcFile%
gawk '{print $1}' %cTagFile%  > %StativRepDec%

cmp -s %StativRepDec% %StativRepDef%
echo errorlevel=%errorlevel%
if "%errorlevel%"=="0" (echo same) else (echo diff)

Since the script is needed very often, I encapsulated it in a console utility prototype_check. This utility is some analogue of the utility BusyBox. Other utilities are called by the key. The script for checking static prototypes will be called by the key csp (check static prototype).

Debugging

This is what the utility log looks like if successful

And this is the log that will appear in case of negative success

The prototype_check utility performs a thorough check and creates two text files to see the defect. Shows which static functions are in the wrong place. Tool(a) actually found a desynchronization in the definitions. This is clearly visible with the WinMerge utility.

Thus, the programmer receives target indication of those static functions that need to be moved one way or another. Now it is clear what to do.

Results

In the end, I managed to develop a unique utility-supervisor, which, like a litmus test, automatically shows the loss of synchronization between the order of announcement and the order of definition static functions in a *.c file in the C programming language.

I love it, brothers, I love it.

It's a pleasure to live, brothers.

With our utility you don't have to worry

I hope the utility prototype_check or cmd script will help other microcontroller programmers to also increase the efficiency of their work in the matter of bringing the code to internal design standards.

If you need this utility, please contact us.

Dictionary

acronym

Transcript

CSV

Comma-separated values

csp

Check Static Prototyping

Links

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *