[splint-discuss] Parse Error on Macro, help

Richard A. O'Keefe ok at cs.otago.ac.nz
Wed Sep 6 01:52:06 EDT 2006


raymond <raymond-xu at 126.com> insists that
	[the double semicolon is]
	not the reason, because I drop the semicolon on the line # 9, it
	still have the same parse error.
	
Let's see what happens when we try some other programs.

a% cat -n fu.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;
     7	
     8	struct any_msg {
     9		MSG_COMMON_HEADER();
    10	};
    11	
    12	int main(int argc , char** argv) {
    13	    struct any_msg msg = { .type = 0, .len = 4 };
    14	
    15	    printf("msg.type = %d msg.len = %d\n", msg.type, msg.len);
    16	    return 0;
    17	}
    18	

First, the Alpha OSF/1 lint checker:

a% lint fu.c
"fu.c", line 9: error: syntax error
"fu.c", line 9: error: structure members must be terminated by ';'
"fu.c", line 10: error: zero sized structure

OK, there really IS a parse error there, splint was right about that.

"fu.c", line 13: error: illegal structure initialization
"fu.c", line 13: error: syntax error

That is, the C99-style struct initialisation really DOESN'T work in C89.

"fu.c", line 15: warning: type undefined
"fu.c", line 15: error: member of structure or union required
"fu.c", line 15: warning: len undefined
"fu.c", line 15: error: member of structure or union required
"fu.c", line 15: error: operator (CALL) in a constant expression
"fu.c", line 12: warning: argument argc unused in function main
"fu.c", line 12: warning: argument argv unused in function main

The rest are cascades.

Now, let's try GCC, with a lot of warnings switched on:

a% glint fu.c
fu.c:9: parse error before `u_int16_t'
fu.c:9: warning: no semicolon at end of struct or union
fu.c:9: warning: type defaults to `int' in declaration of `type'
fu.c:9: ANSI C forbids data definition with no type or storage class

Hmm, that's odd, there seems to be something else going on.
Let's come back to that.

fu.c:9: warning: ANSI C does not allow extra `;' outside of a function
fu.c:10: parse error before `}'
fu.c:10: warning: ANSI C does not allow extra `;' outside of a function

Right, the double semicolon *IS* a problem.
It may not be THE problem, but it is A problem.

fu.c: In function `main':
fu.c:13: variable `msg' has initializer but incomplete type
fu.c:13: unknown field `type' specified in initializer
fu.c:13: warning: excess elements in struct initializer
fu.c:13: warning: (near initialization for `msg')
fu.c:13: unknown field `len' specified in initializer
fu.c:13: warning: excess elements in struct initializer
fu.c:13: warning: (near initialization for `msg')
fu.c:13: storage size of `msg' isn't known
fu.c:13: warning: unused variable `msg'
fu.c:12: warning: unused parameter `argc'
fu.c:12: warning: unused parameter `argv'

Probably cascades from the earlier problems.

So what else is going on?  Let's get the compiler to tell us.

a% glint -E foo.c
<<3300 lines NOT containing any definition of u_int16_t snipped>>
 
struct any_msg {
	u_int16_t len; u_int16_t type; ;
};

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

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

And there is the problem.
<unistd.h> DOES NOT DEFINE u_int16_t (I have checked POSIX)
<stdio.h>  DOES NOT DEFINE u_int16_t (I have checked C89)
<stdlib.h> DOES NOT DEFINE u_int16_t (I have checked C89)
In fact, NOTHING in this program defines u_int16_t.

More than that, even C99 doesn't define any u_int16_t.
There _is_ a standard header <stdint.h> in C99 which defines,
amongst other types, uint16_t (on a Linux box, try 'man stdint').
Some people prefer <inttypes.h>, which provides more information
about those types, but <inttypes.h> doesn't add any extra types.
There is NOTHING in C99 that provides u_int16_t.

I have now checked on Fedora Linux, Alpha OSF/1, MacOS X, and Solaris 2.9.
In none of them does this compile with any C compiler, including ones
like gcc and Sun C that claim to be very nearly C99-compatible.

So where is u_int16_t supposed to come from?  It's not C89, it's not C99,
it's not POSIX (the current POSIX, or at any rate the current Single Unix
Specification, is aligned with C99, so would have no reason to define
u_int16_t when uint_16_t is ready to hand), it's not Linux, it's not Solaris,
it's not MacOS X, what _is_ it?

splint is telling you about a very real problem;
it's a pity that the parser doesn't say something like
    u_int_16_t may be intended as a type name but isn't one
instead of falling over in a heap of rubble, but the immediate problem
is definitely in your code, not splint.



More information about the splint-discuss mailing list