[splint-discuss] Parse Error on Macro, help

Richard A. O'Keefe ok at cs.otago.ac.nz
Wed Sep 6 00:51:43 EDT 2006


raymond <raymond-xu at 126.com> wrote:
	I write a simple C program with a Macro like below:
	
	/*test.c*/
	  1 #include<unistd.h>
	  2 #include<stdio.h>
	  3 #include <stdlib.h>
	  4 #define MSG_COMMON_HEADER()                     \
	  5         u_int16_t len;                          \
====>	  6         u_int16_t type;

Note 1: having empty parentheses in a macro definition is technically
undefined in C89.  (I'm not sure, it might be illegal.)

Note 2: your macro ends with a ';'.

	  7
	  8 struct any_msg {
=====>	  9           MSG_COMMON_HEADER ();

Note 3: having empty parentheses in a macro call is technically
undefined in C89.  (I'm not sure, it might be illegal.)
In any case, putting argument parentheses on something which HAS
no arguments and ISN'T intended to be function-like is, um, the
very opposite of good style.  It confuses people.

Note 4: your macro call has ANOTHER ';' after it.

	 10 };
	 11
	 12 int main( int argc , char** argv)
	 13 {
	 14         struct any_msg msg = {
	 15                 .type = 0,
	 16                 .len = 4};
	 17         printf( "msg.type = %d msg.len = %d\n", msg.type,msg.len);
	 18         return 0;
	 19 }
	
	Using the splint cmd:
		splint +posixlib macro_splint.c
	it outputs:
		
	        Splint 3.1.1 --- 06 Jan 2006
	        
	        macro_splint.c:9:13: Parse Error. (For help on parse errors, see
	        splint -help
	                       parseerrors.)
	        *** Cannot continue.
	It seems like splint can't parse the MSG_COMMON_HEADER() macro.
	
It's not the macro, it's the result of macro expansion.
Do it by hand!  What you get is 

	struct any_msg {
	    u_int16_t len;
	    u_int16_t type;;
	};             /* ^^ */

which isn't legal C and never has been.
No conforming C processor can parse this; it is flat out illegal,
and in telling you so, splint is doing no more than its job.

There's one more thing.  Splint is a C89 checker, not a C99 checker.
I'm sure we all long for it to become a C99 checker, and had I world
enough and time I'd be in there hacking it myself.  (Sadly, I don't.)
The construction

	struct any_msg msg = {.type = 0, .len = 4};

is new in C99; C89 did not support any form of named initialisation
for structs, only positional.

What's the right way to do it?

	#include <unistd.h>
	#include <stdio.h>
	#include <stdlib.h>
	#define MSG_COMMON_FIELDS	\
		u_int16_t len;		\
		u_int16_t type;

	struct any_msg {
	    MSG_COMMON_FIELDS
	};

	int main(int argc, char** argv) {
	    struct any_msg msg = {/*len*/ 4, /*type*/ 0};

	    printf("msg.type = %d msg.len = %d\n", msg.type, msg.len);
	    return 0;
	}
	


More information about the splint-discuss mailing list