__builtin_types_compatible_p and 'char *' vs. 'char []'

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I think C's automatic conversion of char[] to char* is trying to drive
me insane :-)

In Asterisk's code, we've got a very simple macro for selecting between
two strings if the first one is NULL or empty:

#define S_OR(a, b) (ast_strlen_zero(a) ? (b) : (a))

However, as written, this macro evaluates 'a' twice, so if it is
actually a function call or has side effects, the results are non-optimal.

I tried to rewrite it as follows:

#define S_OR(a, b) ({typeof(a) __x = a; (ast_strlen_zero(__x) ? (b) :
__x);})

When called like this, it compiles just fine:

	char *str1, *str2;

	....
	str2 = S_OR(str1, "");

In this case, typeof(a) is 'char *', so the declaration "char *__x =
str1;' works great.

However, when called like this, it fails to compile:

	char str1[20], *str2;

	....
	str2 = S_OR(str1, "");

This is because the declaration becomes "char[] __x = str1;', which is
invalid. In the simpler version of the macro this works fine, because
assigning the other way (str2 = str1;) is completely valid, as the
compiler 'promotes' the char[] reference into a char* since they are
the same thing anyway when used as an r-value.

So, in an attempt to be even more clever, I rewrote it as this:

#define S_OR(a, b)
__builtin_choose_expr(__builtin_types_compatible_p(typeof(a), char[]), \
                                         ({char *__x = (a);
(ast_strlen_zero(__x) ? (b) : __x);}), \
                                         ({typeof (a) __x = (a);
(ast_strlen_zero(__x) ? (b) : __x);}))

Unfortunately, this does not accomplish the desired result, because
__builtin_types_compatible_p appears to return 1 (true) for 'char*' and
'char[]'. I suppose in the grand scheme of things this is true, but it's
not helping me accomplish what I want to accomplish :-)

There is one workaround that I've found, which is to call the macro like
this:

	char str1[20], *str2;

	....
	str2 = S_OR(&str1, "");

This makes the 'promotion' to 'char *' explicit, and resolves the issue.
It would require changing about 60 lines of code, which I could deal
with, but if possible I'd really rather come up with a way to make the
macro do the 'right thing'.

Am I just barking up the wrong tree here?

-- 
Kevin P. Fleming
Director of Software Technologies
Digium, Inc. - "The Genuine Asterisk Experience" (TM)

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux