C Syntax Check
Zum (automatisierten) Auffinden von Syntax-Fehlern in C-Programmen á la lint gibt es viele Tools.
splint ist frei verfügar für viele Plattformen, inklusive Windows, Linux und Cygwin (die Windows- und Cygwin-Versionen liefern identischen Output); Informationen und Download siehe unter Weiterführende Links.
Die beiden typischen Zuweisungs-/Test-Fehler im C-Programm aha.c
int main(void)
{
int i=3;
if (i=5)
i==4;
return 0;
}
werden mittels splint aha.c sofort aufgedeckt:
C:\ASURO_src>splint aha.c Splint 3.1.1 --- 02 May 2003 aha.c: (in function main) aha.c:5:7: Test expression for if is assignment expression: i = 5 The condition test is an assignment expression. Probably, you mean to use == instead of =. If an assignment is intended, add an extra parentheses nesting (e.g., if ((a = b)) ...) to suppress this message. (Use -predassign to inhibit warning) aha.c:5:7: Test expression for if not boolean, type int: i = 5 Test expression type is not boolean or int. (Use -predboolint to inhibit warning) aha.c:6:5: Statement has no effect: i == 4 Statement has no visible effect --- no values are modified. (Use -noeffect to inhibit warning) Finished checking --- 3 code warnings
Verwendung von splint für die Asuro-Programmierung
Um Probleme mit dem AVR-Compiler für den Asuro und irgendwelchen weiteren installierten Compilern zu vermeiden, geschieht die Syntax-Überprüfung in zwei Schritten:
- Erzeugen einer (AVR-)C-präprozessierten Datei.
- Aufruf von splint für diese Datei.
Asuro-Beispiel
Die folgende Funktion stammt aus einem Thread im RoboterNetz Asuro-Forum:
void tastenCheck(void)
{
static unsigned char pressed = 0;
unsigned int t1,t2;
PrintInt(switched);
SerPrint("switched 1 \n\r");
if(switched == TRUE && pressed == 0) { // Tastendruck
pressed = 1;
t1 = PollSwitch();
t2 = PollSwitch();
taste = (t1+t2+1)/2;
PrintInt(taste);
PrintInt(switched);
SerPrint("switched 2 \n\r");
}
if(pressed == 1 && switched == TRUE) {
StopSwitch();
switched == 0;
PrintInt(switched);
SerPrint("switched 3 \n\r");
}
if(switched == 0) {
pressed = 0;
StartSwitch();
PrintInt(switched);
SerPrint("switched 4 \n\r");
}
}
Damit splint damit Umgehen kann, muß noch die globale Variable taste definiert und die Asuro-Bibliothek eingebunden werden. Dies liefert das folgende C-Programm sample.c:
#include "asuro.h"
unsigned int taste;
void tastenCheck(void)
{
static unsigned char pressed = 0;
...
...
}
Wie oben beschrieben wird zuerst der AVR-C-Preprocessor aktiviert und die Datei sample.E.c erzeugt:
C:\ASURO_src>avr-gcc -mmcu=atmega8 -E sample.c >sample.E.c
Damit splint nicht durch die #line-Anweisungen in sample.E.c gestört wird, wird die Option -preproc verwendet, und zur Vermeidung von Problemen mit anderen installierten Compilern wird noch die Option -nolib verwendet. Dies liefert erst einmal eine ganze Menge an Meldungen:
C:\ASURO_src>splint -preproc -nolib sample.E.c Splint 3.1.1 --- 02 May 2003 C:/WinAVR/avr/include/stdlib.h: (in function atol) C:/WinAVR/avr/include/stdlib.h:253:31: Null storage passed as non-null param: strtol (..., (char **)0, ...) A possibly null pointer is passed as a parameter corresponding to a formal parameter with no /*@null@*/ annotation. If NULL may be used for this parameter, add a /*@null@*/ annotation to the function parameter declaration. (Use -nullpass to inhibit warning) sample.c: (in function tastenCheck) sample.c:7:35: Variable pressed initialized to type int, expects unsigned char: 0 Types are incompatible. (Use -type to inhibit warning) sample.c:10:13: Function SerPrint expects arg 1 to be unsigned char * gets char *: "switched 1 \n\r" To ignore signs in type comparisons use +ignoresigns sample.c:11:25: Operands of == have incompatible types (unsigned char, int): pressed == 0 sample.c:12:7: Assignment of int to unsigned char: pressed = 1 To make char and int types equivalent, use +charint. sample.c:13:9: Assignment of unsigned char to unsigned int: t1 = PollSwitch() sample.c:14:9: Assignment of unsigned char to unsigned int: t2 = PollSwitch() sample.c:16:16: Function PrintInt expects arg 1 to be int gets unsigned int: taste sample.c:20:16: Function SerPrint expects arg 1 to be unsigned char * gets char *: "switched 2 \n\r" sample.c:23:7: Operands of == have incompatible types (unsigned char, int): pressed == 1 sample.c:25:7: Statement has no effect: switched == 0 Statement has no visible effect --- no values are modified. (Use -noeffect to inhibit warning) sample.c:27:16: Function SerPrint expects arg 1 to be unsigned char * gets char *: "switched 3 \n\r" sample.c:31:7: Assignment of int to unsigned char: pressed = 0 sample.c:34:16: Function SerPrint expects arg 1 to be unsigned char * gets char *: "switched 4 \n\r" C:/WinAVR/avr/include/stdlib.h:94:24: Function exported but not used outside stdlib: abort A declaration is exported, but not used outside this module. Declaration can use static qualifier. (Use -exportlocal to inhibit warning) C:/WinAVR/avr/include/stdlib.h:103:1: Definition of abort C:/WinAVR/avr/include/stdlib.h:249:24: Function exported but not used outside stdlib: atol C:/WinAVR/avr/include/stdlib.h:254:1: Definition of atol sample.c:3:14: Variable exported but not used outside sample: taste Finished checking --- 17 code warnings
Um nun ein bißchen den Überblick zu gewinnen (und erstmal die Anzahl der Warnungen zu drücken) kann man folgende Optionen dazuschalten (diese Optionen kann man dem Manual, splint -help oder aber dem obigen Output entnehmen):
- +charint (macht char- and int-Typen äquivalent)
- +ignoresigns (ignoriert signed/unsigned-Probleme in Vergleichen)
- -exportlocal (ignoriert Export-Warnungen)
Dies reduziert die Warnungen auf 2, eine Ungenauigkeit in der Datei stdlib.h des AVR-Compilers und den echten Fehler:
C:\ASURO_src>splint -preproc -nolib +charint +ignoresigns -exportlocal sample.E. c Splint 3.1.1 --- 02 May 2003 C:/WinAVR/avr/include/stdlib.h: (in function atol) C:/WinAVR/avr/include/stdlib.h:253:31: Null storage passed as non-null param: strtol (..., (char **)0, ...) A possibly null pointer is passed as a parameter corresponding to a formal parameter with no /*@null@*/ annotation. If NULL may be used for this parameter, add a /*@null@*/ annotation to the function parameter declaration. (Use -nullpass to inhibit warning) sample.c: (in function tastenCheck) sample.c:25:7: Statement has no effect: switched == 0 Statement has no visible effect --- no values are modified. (Use -noeffect to inhibit warning) Finished checking --- 2 code warnings
Weiterführende Links
http://www.splint.org/ - Secure Programming Lint Homepage
http://www.roboternetz.de/phpBB2/viewtopic.php?t=29987 - RoboterNetz-Thread zum Thema