Re: determine base type of a typedef
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
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
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
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
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
> 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
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
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
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
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
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
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; > } >