Discussion:
macro expansion and types in <sys/types.h>
Brook Milligan
2014-09-05 04:31:43 UTC
Permalink
I am building a package (samtools if anyone cares) that tries to define some functions with c preprocessor macro expansions. In doing so it uses type names (e.g., uint16_t) as both part of the function name as well as one of the types within the function definition. However, in some but not all places the macro expansion leads to extra underscores being prepended, i.e., uint16_t is sometimes expanded as __uint16_t.

This is clearly a result of lines like the following in <sys/types.h>:

#ifndef uint16_t
typedef __uint16_t uint16_t;
#define uint16_t __uint16_t
#endif

The problem is that the extra underscores that are added to the function names do not match function calls elsewhere without them.

Here is a much simplified example. Running the following through gcc -E

#include <sys/types.h>

#define M0(x) void name_##x() { }
#define M1(x, y) void name_##x(y) { }
#define M2(x) M1(x,x)

M0(uint16_t)
M1(uint16_t,uint16_t)
M2(uint16_t)

yields the following (omitting all the stuff from sys/types.h):

void name_uint16_t() { }
void name_uint16_t(__uint16_t) { }
void name___uint16_t(__uint16_t) { }

I would appreciate some input from the c preprocessor wizards among you regarding how to fix this problem.

Thanks for your help.

Cheers,
Brook
OBATA Akio
2014-09-06 02:24:51 UTC
Permalink
Hi,
Post by Brook Milligan
I am building a package (samtools if anyone cares) that tries to define some functions with c preprocessor macro expansions. In doing so it uses type names (e.g., uint16_t) as both part of the function name as well as one of the types within the function definition. However, in some but not all places the macro expansion leads to extra underscores being prepended, i.e., uint16_t is sometimes expanded as __uint16_t.
#ifndef uint16_t
typedef __uint16_t uint16_t;
#define uint16_t __uint16_t
#endif
It's also in <stdint.h>.

I feel it is bad idea to define it in both sys/types.h and stdint.h, and use "uint16_t"
as a multiple definition guard name.
Post by Brook Milligan
The problem is that the extra underscores that are added to the function names do not match function calls elsewhere without them.
Here is a much simplified example. Running the following through gcc -E
#include <sys/types.h>
#define M0(x) void name_##x() { }
#define M1(x, y) void name_##x(y) { }
#define M2(x) M1(x,x)
M0(uint16_t)
M1(uint16_t,uint16_t)
M2(uint16_t)
void name_uint16_t() { }
void name_uint16_t(__uint16_t) { }
void name___uint16_t(__uint16_t) { }
I would appreciate some input from the c preprocessor wizards among you regarding how to fix this problem.
Thanks for your help.
I don't know your situation well, but I've added following patches for the issue:
devel/gobject-introspection/patches/patch-aa
lang/jamvm/patches/patch-src_interp_engine_interp.h
--
OBATA Akio / ***@lins.jp
Brook Milligan
2014-09-06 04:10:08 UTC
Permalink
Thanks.
Post by OBATA Akio
devel/gobject-introspection/patches/patch-aa
lang/jamvm/patches/patch-src_interp_engine_interp.h
I came up with something similar: call the macros with, for example, __uint16_t instead of the original uint16_t and fix the call sites to use the underscores. It seems to work in this case.

Cheers,
Brook
Alan Barrett
2014-09-06 10:32:06 UTC
Permalink
Post by Brook Milligan
#ifndef uint16_t
typedef __uint16_t uint16_t;
#define uint16_t __uint16_t
#endif
It's allowed for a macro to be #define'd as itself[*]. Then testing it
with #ifdef works, but expanding it doesn't change anything.

So, we could rewrite the above code as follows:

#ifndef uint16_t
typedef __uint16_t uint16_t;
#define uint16_t uint16_t
#endif

[*] ISO C99 section 6.10.3.4 [...] If the name of the macro
being replaced is found during this scan of the replacement
list [...], it is not replaced. Furthermore, if any nested
replacements encounter the name of the macro being replaced,
it is not replaced.

--apb (Alan Barrett)
Brook Milligan
2014-09-06 13:42:20 UTC
Permalink
Post by Alan Barrett
Post by Brook Milligan
#ifndef uint16_t
typedef __uint16_t uint16_t;
#define uint16_t __uint16_t
#endif
It's allowed for a macro to be #define'd as itself[*]. Then testing it
with #ifdef works, but expanding it doesn't change anything.
#ifndef uint16_t
typedef __uint16_t uint16_t;
#define uint16_t uint16_t
#endif
[*] ISO C99 section 6.10.3.4 [...] If the name of the macro being replaced is found during this scan of the replacement list [...], it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced.
If we were to do this, I believe it would solve the problem I am currently having as the "public" identifiers, e.g., uint16_t, wouldn't be replaced. It also seems like many (all?) uses of __unit16_t would do the right thing. Perhaps those that don't are errors anyway, because __uint16_t and the like are implementation defined?

What are the implications of making a change like this?

Cheers,
Brook
Alan Barrett
2014-09-08 10:10:42 UTC
Permalink
Post by Brook Milligan
It's allowed for a macro to be #define'd as itself [...]
#ifndef uint16_t
typedef __uint16_t uint16_t;
#define uint16_t uint16_t
#endif
If we were to do this, I believe it would solve the problem I am
currently having as the "public" identifiers, e.g., uint16_t,
wouldn't be replaced. It also seems like many (all?) uses
of __unit16_t would do the right thing. Perhaps those that
don't are errors anyway, because __uint16_t and the like are
implementation defined?
What are the implications of making a change like this?
I am not aware of any adverse consequences, and several parts of
the NetSBD system include files could be simplified. Somebody
just needs to do the work, and discuss it in tech-userlevel.

--apb (Alan Barrett)
Martin Husemann
2014-09-08 10:25:03 UTC
Permalink
Post by Alan Barrett
I am not aware of any adverse consequences, and several parts of
the NetSBD system include files could be simplified. Somebody
just needs to do the work, and discuss it in tech-userlevel.
I think several pkgs have patches to work around it and could be simplified
(sometime in the future). Firefox is one.

Martin

Loading...