Re: determine base type of a typedef

2020-10-26 Thread Paul Eggert

On 10/26/20 8:48 AM, Bob Friesenhahn wrote:
The approach that Paul Eggert suggests is very interesting, but it might not 
provide absolute proof of the C type since the compiler/linker might allow 
success if the types are the same size.


Not a problem in practice. The C standard requires a diagnostic if the types 
don't match, and this sort of type checking should be the same checking that the 
compiler uses for printf.




Re: determine base type of a typedef

2020-10-26 Thread Bob Friesenhahn

On Fri, 23 Oct 2020, Vivien Kraus wrote:


Is it not possible to always use "%lld" and always convert the
arguments to (long long int)?


The way I have been doing things for many years is to get the size of 
the underlying type and then include a cast in the printf arguments to 
a type of the same size.  The need to add a cast is a bit messy, but 
then then again, just about everything related to printf is messy.


So create a define for the time_t formatter, and a define/typedef for 
the type to cast to.


The approach that Paul Eggert suggests is very interesting, but it 
might not provide absolute proof of the C type since the 
compiler/linker might allow success if the types are the same size.  A 
printf syntax checker might not use the same rules.


Anything involving executing code should be avoided as much as 
possible since it hurts cross compilation.


Anything involving recent C standards should be avoided since it harms 
portability.


Bob
--
Bob Friesenhahn
bfrie...@simple.dallas.tx.us, http://www.simplesystems.org/users/bfriesen/
GraphicsMagick Maintainer,http://www.GraphicsMagick.org/
Public Key, http://www.simplesystems.org/users/bfriesen/public-key.txt



Re: determine base type of a typedef

2020-10-25 Thread Paul Eggert

On 10/25/20 3:00 PM, Anatoli wrote:

If I understand you correctly, I should use something like AC_COMPILE_IFELSE 
with the code with a redefine as you specified, right?


Yes, that's the idea.



Re: determine base type of a typedef

2020-10-25 Thread Anatoli
Nick,

Thanks for your suggestions! They gave me some additional keywords to search for
more ideas.

After trying your code I found that I could actually use _Generic directly in
the C sources, no need for autoconf, e.g.:

time_t _unused_t;
#define TIME_T_FMT _Generic((_unused_t), long long int: "%lld", long int: 
"%ld", int: "%d")

Or even a generic int type format specifier handler:

#define _FTM(x) _Generic((x), long long int: "%lld", long int: "%ld", int: 
"%d", \
unsigned long long int: "%llu", unsigned long int: "%lu", unsigned int: "%u")

And for the case when we can't rely on C11, I just found there's
__builtin_types_compatible_p available since at least gcc 3.1.1 (2002) and 
cland 1.0:

#define TIME_T_FMT (__builtin_types_compatible_p(time_t, long long int) ? 
"%lld" : \
__builtin_types_compatible_p(time_t, long int) ? "%ld" : 
"%d")


On 23/10/20 15:03, Nick Bowler wrote:
> On 2020-10-23, Nick Bowler  wrote:
>> On 23/10/2020, Paul Eggert  wrote:
>>> On 10/22/20 6:09 PM, Russell Shaw wrote:
 else if(sizeof(time_t) == sizeof(long int)) {
>>>
>>> This is not the right kind of test. You want to test whether time_t and
>>> int
>>> are
>>> the same types, not whether they're the same size. To do that, you should
>>> use
>>> code like this:
>>>
>>> extern time_t foo;
>>> extern long int foo;
>>>
>>> Of course this means you'll need to compile N programs rather than
>>> one, but that's life in the big Autoconf city.
>>
>> To improve configure performance when N is more than one or two,
>> you can use C11 _Generic and AC_COMPUTE_INT to pretty easily and
>> quickly determine which type (out of a finite list of candidates)
>> time_t or any other type is compatible with.
>>
>> But you'd need a fallback (probably by compiling one program
>> like the one shown abovce for each type) to handle the case
>> where _Generic is not supported by the implementation.
>>
>> Example (totally untested):
>>
>>   AC_COMPUTE_INT([timetype],
>> [_Generic((time_t)0, long long: 3, default: 0)
>>   + _Generic((time_t)0, long: 2, default: 0)
>>   + _Generic((time_t)0, int: 1, default: 0)],
> 
> On review, it is obvious this list of types could be more succinctly
> written with a single _Generic as they are all for sure different:
> 
>   _Generic((time_t)0, long long: 3, long: 2, int: 1, default: 0)
> 
> But care must be taken if any of the generic cases are themselves
> typedefs, (for example, if we wanted to determine whether POSIX
> ssize_t is compatible with a list of types that includes ptrdiff_t),
> as it is an error to include compatible types among the list of
> cases:
> 
>   /* error if ptrdiff_t happens to be compatible with long long */
>   _Generic((ssize_t)0, long long: 2, ptrdiff_t: 1, default: 0)
> 
> Nesting avoids this problem better than adding as I did originally:
> 
>   _Generic((ssize_t)0, long long: 2, default:
> _Generic((ssize_t)0, ptrdiff_t: 1, default: 0))
> 
> as only one "branch" can be matched.
> 
>> [#include ],
>> [... slow fallback computation goes here])
>>
>>   AS_CASE([$timetype],
>> [3], [... action when time_t is compatible with long long],
>> [2], [... action when time_t is compatible with long],
>> [1], [... action when time_t is compatible with int],
>> [... action when time_t's compatibility is undetermined])
> 
> Cheers,
>   Nick
> 



Re: determine base type of a typedef

2020-10-25 Thread Anatoli
Paul,

Thanks for your suggestion.

If I understand you correctly, I should use something like AC_COMPILE_IFELSE 
with the code with a redefine as you specified, right?

Something like:

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include 
extern time_t foo;
extern long long int foo;]],[[]])],time_fmt="%lld",
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include 
extern time_t foo;
extern long int foo;]],[[]])],time_fmt="%ld",time_fmt="-")
)


On 23/10/20 14:16, Paul Eggert wrote:
> On 10/22/20 6:09 PM, Russell Shaw wrote:
>>     else if(sizeof(time_t) == sizeof(long int)) { 
> 
> This is not the right kind of test. You want to test whether time_t and int 
> are the same types, not whether they're the same size. To do that, you should 
> use code like this:
> 
> extern time_t foo;
> extern long int foo;
> 
> Of course this means you'll need to compile N programs rather than one, but 
> that's life in the big Autoconf city.
> 



Re: determine base type of a typedef

2020-10-23 Thread Nick Bowler
On 2020-10-23, Nick Bowler  wrote:
> On 23/10/2020, Paul Eggert  wrote:
>> On 10/22/20 6:09 PM, Russell Shaw wrote:
>>> else if(sizeof(time_t) == sizeof(long int)) {
>>
>> This is not the right kind of test. You want to test whether time_t and
>> int
>> are
>> the same types, not whether they're the same size. To do that, you should
>> use
>> code like this:
>>
>> extern time_t foo;
>> extern long int foo;
>>
>> Of course this means you'll need to compile N programs rather than
>> one, but that's life in the big Autoconf city.
>
> To improve configure performance when N is more than one or two,
> you can use C11 _Generic and AC_COMPUTE_INT to pretty easily and
> quickly determine which type (out of a finite list of candidates)
> time_t or any other type is compatible with.
>
> But you'd need a fallback (probably by compiling one program
> like the one shown abovce for each type) to handle the case
> where _Generic is not supported by the implementation.
>
> Example (totally untested):
>
>   AC_COMPUTE_INT([timetype],
> [_Generic((time_t)0, long long: 3, default: 0)
>   + _Generic((time_t)0, long: 2, default: 0)
>   + _Generic((time_t)0, int: 1, default: 0)],

On review, it is obvious this list of types could be more succinctly
written with a single _Generic as they are all for sure different:

  _Generic((time_t)0, long long: 3, long: 2, int: 1, default: 0)

But care must be taken if any of the generic cases are themselves
typedefs, (for example, if we wanted to determine whether POSIX
ssize_t is compatible with a list of types that includes ptrdiff_t),
as it is an error to include compatible types among the list of
cases:

  /* error if ptrdiff_t happens to be compatible with long long */
  _Generic((ssize_t)0, long long: 2, ptrdiff_t: 1, default: 0)

Nesting avoids this problem better than adding as I did originally:

  _Generic((ssize_t)0, long long: 2, default:
_Generic((ssize_t)0, ptrdiff_t: 1, default: 0))

as only one "branch" can be matched.

> [#include ],
> [... slow fallback computation goes here])
>
>   AS_CASE([$timetype],
> [3], [... action when time_t is compatible with long long],
> [2], [... action when time_t is compatible with long],
> [1], [... action when time_t is compatible with int],
> [... action when time_t's compatibility is undetermined])

Cheers,
  Nick



Re: determine base type of a typedef

2020-10-23 Thread Nick Bowler
On 23/10/2020, Paul Eggert  wrote:
> On 10/22/20 6:09 PM, Russell Shaw wrote:
>> else if(sizeof(time_t) == sizeof(long int)) {
>
> This is not the right kind of test. You want to test whether time_t and int
> are
> the same types, not whether they're the same size. To do that, you should
> use
> code like this:
>
> extern time_t foo;
> extern long int foo;
>
> Of course this means you'll need to compile N programs rather than
> one, but that's life in the big Autoconf city.

To improve configure performance when N is more than one or two,
you can use C11 _Generic and AC_COMPUTE_INT to pretty easily and
quickly determine which type (out of a finite list of candidates)
time_t or any other type is compatible with.

But you'd need a fallback (probably by compiling one program
like the one shown abovce for each type) to handle the case
where _Generic is not supported by the implementation.

Example (totally untested):

  AC_COMPUTE_INT([timetype],
[_Generic((time_t)0, long long: 3, default: 0)
  + _Generic((time_t)0, long: 2, default: 0)
  + _Generic((time_t)0, int: 1, default: 0)],
[#include ],
[... slow fallback computation goes here])

  AS_CASE([$timetype],
[3], [... action when time_t is compatible with long long],
[2], [... action when time_t is compatible with long],
[1], [... action when time_t is compatible with int],
[... action when time_t's compatibility is undetermined])

Cheers,
  Nick



Re: determine base type of a typedef

2020-10-23 Thread Paul Eggert

On 10/22/20 6:09 PM, Russell Shaw wrote:
else if(sizeof(time_t) == sizeof(long int)) { 


This is not the right kind of test. You want to test whether time_t and int are 
the same types, not whether they're the same size. To do that, you should use 
code like this:


extern time_t foo;
extern long int foo;

Of course this means you'll need to compile N programs rather than one, but 
that's life in the big Autoconf city.




Re: determine base type of a typedef

2020-10-23 Thread Anatoli
Yeah, though the idea is not to silence the compiler, but to find a solution to 
the problem and make the compiler happy.

On 23/10/20 06:19, Peter Johansson wrote:
> 
> On 23/10/20 6:39 pm, Russell Shaw wrote:
>> If the compiler complains, then maybe you could capture that complaint 
>> output.
>>
>> Bit of a messy test.
> 
> When trying to detect compiler warnings, I've found AC_LANG_WERROR useful
> 
> https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/autoconf.html#Generic-Compiler-Characteristics
> 
> Peter
> 
> 



Re: determine base type of a typedef

2020-10-23 Thread Peter Johansson



On 23/10/20 6:39 pm, Russell Shaw wrote:
If the compiler complains, then maybe you could capture that complaint 
output.


Bit of a messy test.


When trying to detect compiler warnings, I've found AC_LANG_WERROR useful

https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/autoconf.html#Generic-Compiler-Characteristics

Peter




Re: determine base type of a typedef

2020-10-23 Thread Anatoli
> Is it not possible to always use "%lld" and always convert the
> arguments to (long long int)?

This is what I'm doing right now. GCC on Linux doesn't generate any
warnings in any case, though I'm not sure this is a clean way of doing
things, taking into account Clang on other archs and platforms. I'm
investigating it right now. That's why the initial question.

With respect to converting the arguments to (long long int), if I
understand you correctly, you suggest to cast the values? This is not
the desired way of solving this type of things.

I'll quote Ellie Timoney here:

>From a maintenance point of view, casting usually means "there's
something tricky going on here; treat carefully". If we start littering
every formatted string with casts, it becomes impossible to tell which
ones are actually something tricky, and which ones are just annoying
platform workarounds. The right place for platform workarounds is
configure.ac


On 23/10/20 04:00, Vivien Kraus wrote:
> Hello Anatoli,
> 
> Le jeudi 22 octobre 2020 à 19:23 -0300, Anatoli a écrit :
>> #if (AC_TYPE(time_t) == "long long int")
>> #define TIME_T_FMT "%lld"
>> #elif (AC_TYPE(time_t) == "long int")
>> #define TIME_T_FMT "%ld"
>> #else
>> #error dont know what to use for TIME_T_FMT
>> #endif
> 
> Is it not possible to always use "%lld" and always convert the
> arguments to (long long int)?
> 
> Best regards,
> 
> divoplade
> 
> 



Re: determine base type of a typedef

2020-10-23 Thread Russell Shaw

On 23/10/20 6:06 pm, Russell Shaw wrote:

On 23/10/20 5:54 pm, Anatoli wrote:

Russell,

Thanks for your suggestion. The problem is, as I mentioned in the initial
post, on amd64 sizeof(time_t) is always 8 bytes, as well as long and long
long, so sizeof(time_t) == sizeof(long int) == sizeof(long long int).

I've actually tried the following directly in configure.ac (for this test
it's not needed to run a custom code):

#if (SIZEOF_TIME_T == SIZEOF_LONG_LONG_INT) #define TIME_T_FMT "%lld" #elif
(SIZEOF_TIME_T == SIZEOF_LONG) #define TIME_T_FMT "%ld" #else #error dont
know what to use for TIME_T_FMT #endif

But both checks are true so it makes no sense.

I need something that would not depend on the size of the type. Not sure it's
even possible.

I might be missing something simple because i got up too early.

If a platform has time_t the same size as a long and long long, does it matter 
whether the printf uses "%ld" or "%lld" ?


[For GNU C this is "the same" as both are of 8 bytes, but clang generates a 
warning like: "warning: format specifies type 'long' but the argument has type 
'time_t' (aka 'long long')".]


I see that is the actual problem.

If the compiler complains, then maybe you could capture that complaint output.

Bit of a messy test.



Re: determine base type of a typedef

2020-10-23 Thread Russell Shaw

On 23/10/20 6:06 pm, Russell Shaw wrote:

On 23/10/20 5:54 pm, Anatoli wrote:

Russell,

Thanks for your suggestion. The problem is, as I mentioned in the initial
post, on amd64 sizeof(time_t) is always 8 bytes, as well as long and long
long, so sizeof(time_t) == sizeof(long int) == sizeof(long long int).

I've actually tried the following directly in configure.ac (for this test
it's not needed to run a custom code):

#if (SIZEOF_TIME_T == SIZEOF_LONG_LONG_INT) #define TIME_T_FMT "%lld" #elif
(SIZEOF_TIME_T == SIZEOF_LONG) #define TIME_T_FMT "%ld" #else #error dont
know what to use for TIME_T_FMT #endif

But both checks are true so it makes no sense.

I need something that would not depend on the size of the type. Not sure it's
even possible.

I might be missing something simple because i got up too early.

If a platform has time_t the same size as a long and long long, does it matter 
whether the printf uses "%ld" or "%lld" ?


[For GNU C this is "the same" as both are of 8 bytes, but clang generates a 
warning like: "warning: format specifies type 'long' but the argument has type 
'time_t' (aka 'long long')".]


I see that is the actual problem.



Re: determine base type of a typedef

2020-10-23 Thread Anatoli
Russell,

> If a platform has time_t the same size as a long and long long, does
> it matter whether the printf uses "%ld" or "%lld" ?

>From my first mail:

> For GNU C this is "the same" as both are of 8 bytes, but clang
> generates a warning like: "warning: format specifies type 'long' but
> the argument has type 'time_t' (aka 'long long')".

Clang warns that it's not OK, though I'm not sure why exactly.


On 23/10/20 04:06, Russell Shaw wrote:
> On 23/10/20 5:54 pm, Anatoli wrote:
>> Russell,
>>
>> Thanks for your suggestion. The problem is, as I mentioned in the initial
>> post, on amd64 sizeof(time_t) is always 8 bytes, as well as long and long
>> long, so sizeof(time_t) == sizeof(long int) == sizeof(long long int).
>>
>> I've actually tried the following directly in configure.ac (for this test
>> it's not needed to run a custom code):
>>
>> #if (SIZEOF_TIME_T == SIZEOF_LONG_LONG_INT) #define TIME_T_FMT "%lld" #elif
>> (SIZEOF_TIME_T == SIZEOF_LONG) #define TIME_T_FMT "%ld" #else #error dont
>> know what to use for TIME_T_FMT #endif
>>
>> But both checks are true so it makes no sense.
>>
>> I need something that would not depend on the size of the type. Not sure it's
>> even possible.
> I might be missing something simple because i got up too early.
> 
> If a platform has time_t the same size as a long and long long, does it 
> matter whether the printf uses "%ld" or "%lld" ?
> 



Re: determine base type of a typedef

2020-10-23 Thread Russell Shaw

On 23/10/20 5:54 pm, Anatoli wrote:

Russell,

Thanks for your suggestion. The problem is, as I mentioned in the initial
post, on amd64 sizeof(time_t) is always 8 bytes, as well as long and long
long, so sizeof(time_t) == sizeof(long int) == sizeof(long long int).

I've actually tried the following directly in configure.ac (for this test
it's not needed to run a custom code):

#if (SIZEOF_TIME_T == SIZEOF_LONG_LONG_INT) #define TIME_T_FMT "%lld" #elif
(SIZEOF_TIME_T == SIZEOF_LONG) #define TIME_T_FMT "%ld" #else #error dont
know what to use for TIME_T_FMT #endif

But both checks are true so it makes no sense.

I need something that would not depend on the size of the type. Not sure it's
even possible.

I might be missing something simple because i got up too early.

If a platform has time_t the same size as a long and long long, does it matter 
whether the printf uses "%ld" or "%lld" ?




Re: determine base type of a typedef

2020-10-23 Thread Vivien Kraus
Hello Anatoli,

Le jeudi 22 octobre 2020 à 19:23 -0300, Anatoli a écrit :
> #if (AC_TYPE(time_t) == "long long int")
> #define TIME_T_FMT "%lld"
> #elif (AC_TYPE(time_t) == "long int")
> #define TIME_T_FMT "%ld"
> #else
> #error dont know what to use for TIME_T_FMT
> #endif

Is it not possible to always use "%lld" and always convert the
arguments to (long long int)?

Best regards,

divoplade




Re: determine base type of a typedef

2020-10-23 Thread Anatoli
Russell,

Thanks for your suggestion. The problem is, as I mentioned in the initial post, 
on amd64 sizeof(time_t) is always 8 bytes, as well as long and long long, so 
sizeof(time_t) == sizeof(long int) == sizeof(long long int).

I've actually tried the following directly in configure.ac (for this test it's 
not needed to run a custom code):

#if (SIZEOF_TIME_T == SIZEOF_LONG_LONG_INT)
#define TIME_T_FMT "%lld"
#elif (SIZEOF_TIME_T == SIZEOF_LONG)
#define TIME_T_FMT "%ld"
#else
#error dont know what to use for TIME_T_FMT
#endif

But both checks are true so it makes no sense.

I need something that would not depend on the size of the type. Not sure it's 
even possible.

Thanks anyway.

Regards,
Anatoli


On 22/10/20 22:09, Russell Shaw wrote:
> 
> On 23/10/20 9:23 am, Anatoli wrote:
>> Hi All,
>>
>> Is there a way to determine with autoconf what's the base type of a typedef?
>>
>> I'm trying to accomplish the following:
>>
>> There are standard types time_t, off_t, size_t and similar that are defined
>> differently on different platforms/OS.
>>
>> For example, time_t is defined as "long int" on Linux amd64, but as "long
>> long int" on OpenBSD amd64. So when printing a time_t var with printf & co,
>> on Linux it's OK to use "%ld" format specifier, but on OpenBSD it should be
>> "%lld".
> You could use an AC_COMPILE thing to run a small bit of C that does something 
> like:
> 
> int
> test(int argc, char **argv)
> {
>     time_t t = -1;
> 
>     if(t < 0) {
> if(sizeof(time_t) == sizeof(int)) {
>     printf("d");
> }
> else if(sizeof(time_t) == sizeof(long int)) {
>     printf("ld");
> }
> else if(sizeof(time_t) == sizeof(long long int)) {
>     printf("lld");
> }
> else {
>     printf("error");
> }
>     }
>     else {
> if(sizeof(time_t) == sizeof(int)) {
>     printf("u");
> }
> else if(sizeof(time_t) == sizeof(long int)) {
>     printf("lu");
> }
> else if(sizeof(time_t) == sizeof(long long int)) {
>     printf("llu");
> }
> else {
>     printf("error");
> }
>     }
> 
>     return 0;
> }
> 



Re: determine base type of a typedef

2020-10-22 Thread Russell Shaw



On 23/10/20 9:23 am, Anatoli wrote:

Hi All,

Is there a way to determine with autoconf what's the base type of a typedef?

I'm trying to accomplish the following:

There are standard types time_t, off_t, size_t and similar that are defined
differently on different platforms/OS.

For example, time_t is defined as "long int" on Linux amd64, but as "long
long int" on OpenBSD amd64. So when printing a time_t var with printf & co,
on Linux it's OK to use "%ld" format specifier, but on OpenBSD it should be
"%lld".

You could use an AC_COMPILE thing to run a small bit of C that does something 
like:

int
test(int argc, char **argv)
{
time_t t = -1;

if(t < 0) {
if(sizeof(time_t) == sizeof(int)) {
printf("d");
}
else if(sizeof(time_t) == sizeof(long int)) {
printf("ld");
}
else if(sizeof(time_t) == sizeof(long long int)) {
printf("lld");
}
else {
printf("error");
}
}
else {
if(sizeof(time_t) == sizeof(int)) {
printf("u");
}
else if(sizeof(time_t) == sizeof(long int)) {
printf("lu");
}
else if(sizeof(time_t) == sizeof(long long int)) {
printf("llu");
}
else {
printf("error");
}
}

return 0;
}