Synchronizing the order of function declarations and definitions

Prologue

We have a rule for formatting source files in our organization, which sounds like this:

The order of function declarations must match the order of function definitions.

What's the problem?

It is clear that this requirement does not affect the program's behavior during execution. It does not make the code execution any better or worse. But it requires additional efforts, resources and time for its execution.

But since this requirement exists here, it has to be put forward, no matter what. This creates a number of problems

  1. The GCC compiler does not have any switches that would detect different orders in function declarations and definitions.

  2. The CppCheck static analyzer does not have such keys to detect different orders in the declaration and definition of functions

  3. The Understand static analyzer (scitools) does not have such keys to detect different orders in the declaration and definition of functions

  4. It is also obvious that the problem is that it is very tedious to manually identify places where this strange sterile rule is violated. It is obvious that it would be great to create a console utility that would automatically show and prove that this notorious order of declaration and definition does not match.

That's why I decided to write such a utility. There is a need for it.

Statement of the problem

Write a console utility that will inform the programmer about violations of the sequence of declaration and definition of functions in C programs.

The utility should be easy to work with. You literally give it a *.c file,

prototype_check.exe cgp dds.c

and the utility itself finds the *.h file of the same name, reads the declaration sequences and reads the function definition sequences, compares them and signals an error in the form of a return code (0 – success 1 error).

Terminology

Before moving on, there are a few things to remember.

tag (token) – is a text string that can be either a function name or a variable name.

CygWin – a set of Unix utilities for the Windows operating system

What do you need from the software?

I'm going to solve this problem with the most common tools from CygWin

No.

Utility name

Purpose

1

сtags

Creates a file with a list of tags for a given programming language. A sort of source code indexer.

2

awk/gawk

programmable text string analyzer

3

sed

utility for automatic deletion or automatic replacement of lines in text files

4

FC

console file comparison utility

5

cmp

utility for comparing text files

6

r.m.

file deletion utility

What's the plan?

I propose to solve the problem by building a four-stage software pipeline like this one.

Implementation

There is one old and very useful utility. It is called ctags. This is essentially an analyzer of tokens in different programming languages. In particular, you can get a list of functions inside a *.c file using the utility сtags. The tags utility can be extracted from CygWin

After installation ctags you need to write the path to the CygWin utilities (C:\cygwin64\bin) in the PATH variable. After that, the where utility should find the ctags utility

C:\Users\Name>where ctags
C:\cygwin64\bin\ctags.exe

What keys should I use to run ctags?

No.

Utility key

Key action

1

–sort=no

Do not sort rows in the output table with the report

2

-fxxxxx

Write report to file xxxxx

3

-x –c-types=f

Generate a report on C programming language functions

Phase 1: Get a list of all functions in the C file

After processing the *.c file with such keys, the following report appears in the form of a table

output of ctags.exe utility for *.c file
DDS_GetNode      function    151 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c DDS_HANDLE* DDS_GetNode(const U8 num)
DDS_CalcSinSample function    187 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c FLOAT32 DDS_CalcSinSample(const U64 upTimeUs,
DDS_Ctrl         function    216 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_Ctrl(const U8 num,
DDS_Init         function    249 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_Init(void)
DDS_InitOne      function    289 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_InitOne(const U8 num)
DDS_Play         function    339 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_Play(const U8 num,
DDS_Play1kHz     function    388 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_Play1kHz(const U8 num,
DDS_Proc         function    414 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_Proc(void)
DDS_SetArray     function    454 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_SetArray(const U8 num,
DDS_SetFence     function    513 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_SetFence(const U8 num,
DDS_SetFramePerSec function    546 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_SetFramePerSec(const U8 num,
DDS_SetPattern   function    572 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_SetPattern(const U8 num,
DDS_SetPwm       function    602 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_SetPwm(const U8 num,
DDS_SetSaw       function    641 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_SetSaw(const U8 num,
DDS_SetSin       function    676 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_SetSin(const U8 num,
DDS_Stop         function    717 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c STD_RESULT DDS_Stop(const U8 num)
DDS_GetConfig    function    753 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c const DDS_CONFIG* DDS_GetConfig(const U8 num)
DDS_ProcOne      function    791 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static STD_RESULT DDS_ProcOne(const U8 num)
DDS_OnOffToState function    838 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static DDS_STATE DDS_OnOffToState(const U8 onOff)
DDS_IsValidPlayer function    868 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static STD_RESULT DDS_IsValidPlayer(const DDS_PLAYER player)
DDS_IsValidSignal function    919 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static STD_RESULT DDS_IsValidSignal(const DDS_SIGNAL ddsSignal)
DDS_IsValidFramePattern function    967 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static STD_RESULT DDS_IsValidFramePattern(const DDS_SAMPLE_PATTERN samplePattern)
DDS_IsValidConfig function   1005 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static STD_RESULT DDS_IsValidConfig(const DDS_CONFIG* const Config)
DDS_IsValidSampleBitness function   1119 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static STD_RESULT DDS_IsValidSampleBitness(const U8 sampleBitness)
DDS_CalcMaxTimeNs function   1156 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static U32 DDS_CalcMaxTimeNs(DDS_HANDLE* const Node,
DDS_CalcOneSampleLowLevel function   1182 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static DDS_SAMPLE_TYPE DDS_CalcOneSampleLowLevel(DDS_HANDLE* const Node,
DDS_CalcStoreOneSampleLowLevel function   1231 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static STD_RESULT DDS_CalcStoreOneSampleLowLevel(DDS_HANDLE* const Node,
DDS_PlayerToI2sNum function   1275 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static S16 DDS_PlayerToI2sNum(const DDS_PLAYER player)
DDS_SetValidFreq function   1317 C:/projects/code_base_workspace/era_test/source/third_party/computing/dds/dds.c static FLOAT32 DDS_SetValidFreq(const FLOAT32 frequencyHz)

As you can see, the order of listing functions in the report matches the order of their definition in the source C file.

Phase 2: Remove Static Functions

From the report, you need to remove the lines that are responsible for local functions. This can be done using the sed utility

sed -i '/static/d' cTagFunctionReport.txt

Phase 3: Extract only function names

All auxiliary information should be removed from the report: line number, file path, piece of text. This can be done with the awk utility. Like this.

gawk '{print $1}' cTagFunctionReport.txt > ctags_function_report_c_functions.txt

After this, you get a clean file with a list of function names.

list of functions with order preservation
DDS_GetNode
DDS_CalcSinSample
DDS_Ctrl
DDS_Init
DDS_InitOne
DDS_Play
DDS_Play1kHz
DDS_Proc
DDS_SetArray
DDS_SetFence
DDS_SetFramePerSec
DDS_SetPattern
DDS_SetPwm
DDS_SetSaw
DDS_SetSin
DDS_Stop
DDS_GetConfig

Now you need to do the same thing only for the h file.

Phase 4: Generate ctags report for *.h file

Generate a report on functions for the *.h file. Note that the option is different here (–kinds-c=fp).

ctags.exe  --sort=no --kinds-c=fp -fctagsReport.txt dds.h

Phase 5: Remove Preamble

It is necessary to remove the preamble from the report. The preamble contains a couple of exclamation marks. Therefore, it is easy to do. We delete all lines that contain an exclamation mark

sed -i '/!/d' ctagsReport.txt

Phase 6: Extract only features

Select only functions from the report. This is essentially the first column.

gawk '{print $1}' dds.txt > dds_h_functions.txt

Phase 7: Compare declaration and definition sequences

Since the actual sequences of declarations and definitions were crystallized in the files dds_h_functions.txt dds_c_functions.txt, the task was reduced to a simple comparison of text files.

cmp -s dds_h_functions.txt dds_c_functions.txt

If 0, then the files are the same.

Full script

The script on CMD looks like this

set file_h=dds.h
set cTagFile=cTag.txt
"" > %cTagFile%
set FunctionListInC=cFunctions.txt
set file_c=dds.c
set options=--sort=no
set options=%options% -x --c-types=f
set options=%options% -w
set options=%options% -f%cTagFile%
ctags.exe   %options%  %file_c%
sed -i '/static/d' %cTagFile%
gawk '{print $1}' %cTagFile% > %FunctionListInC%
set FunctionListInH=hFunctions.txt
set hTagFile=hTag.txt
"" > %hTagFile%
set options_h=--sort=no
set options_h=%options_h% --kinds-c=fp
set options_h=%options_h% -f%hTagFile%
ctags.exe   %options_h%  %file_h%
sed -i '/!/d' %hTagFile%
gawk '{print $1}' %hTagFile% > %FunctionListInH%
cmp -s %FunctionListInH% %FunctionListInC%
echo errorlevel=%errorlevel%
if "%errorlevel%"=="0" (echo same) else (echo diff)

However, I don't really like the script implementation. You can get into the script with your feet and trample it so much that it stops working. That's why I wrote a software mixture in C to solve this particular problem. No more, no less. I called the utility prototype_check. The utility simply calls console commands and prints a log.

Debugging the utility

Here is the utility prototype_check found a desynchronization between the sequence of declaration and definition of functions.

The prototype_check utility generated the files nau8814_driver_c_functions.txt and nau8814_driver_h_functions.txt, which show which functions exactly failed.

And this is the log of a successful test, which shows that the sequence of function declarations does indeed match the sequence of function definitions. The sequences match.

Results

Managed to make a console utility that allows you to check that the *.h file is in order announcements functions are the same as the order definitions functions in the *.c file.

This utility will allow you to automatically monitor the violation of this notorious requirement for code formatting.

Note that existing technologies were used in developing the tool(s). The utilities are ctags, sed, awk, rm, cmp, cmd and gcc.

If you need such a utility, write. I will send *.exe binary.

Links

Similar Posts

Leave a Reply

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