Author Topic: C macro to determine if a type is signed  (Read 4956 times)

0 Members and 2 Guests are viewing this topic.

Online HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1456
  • Country: gb
C macro to determine if a type is signed
« on: November 12, 2019, 11:24:52 pm »
I need to know at compile-time whether a given type is signed, so I can enable or disable a block of code with an #if.

My first thought - and after some searching around, it turns out also the most common way - was to do the following:

Code: [Select]
#define IS_SIGNED_TYPE(type) (((type)-1) < 0)

But, at least in the scenario I'm attempting to use it in, it doesn't work! :wtf:

As a test, if I do this:

Code: [Select]
#if IS_SIGNED_TYPE(uint16_t)
#warning "Type is signed"
#else
#warning "Type is unsigned"
#endif

My compiler (AVR-GCC) spits out the "Type is signed" message. I'm at a loss to come up with a reason why this fails. What's going wrong here?
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11228
  • Country: us
    • Personal site
Re: C macro to determine if a type is signed
« Reply #1 on: November 12, 2019, 11:52:07 pm »
This macro is for the code. You are trying to use it in a preprocessor. And all the preprocessor stuff is dome with 'int's and there is no typecasting. The preprocessor also does not know what uint16_t is and it is just being substituted whit 0.

You can replace uint16_t with whatever you want. You still essentially get  "(((0)-1) < 0)", which is true in plain integers.
Alex
 

Online HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1456
  • Country: gb
Re: C macro to determine if a type is signed
« Reply #2 on: November 13, 2019, 12:00:43 am »
Ah, I see, thanks. I was starting to suspect it must be something to do with the preprocessor evaluating the expression differently.

Is there any other way of doing such a thing at compile-time?

I can make it a run-time check if I really have to, but ideally I would like to make it compile-time so I can avoid including a whole block of code altogether.
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21609
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: C macro to determine if a type is signed
« Reply #3 on: November 13, 2019, 12:02:27 am »
Remember, macros are just that, macros that are expanded before compilation.

You're actually writing

Code: [Select]
#if (((uint16_t)-1) < 0)

Which doesn't mean very much -- uint16_t isn't a number.  Does it not emit a syntax error?  Perhaps the preprocessor doesn't emit syntax errors on expressions (should be easy enough to look up, I don't know offhand).  I would guess it's evaluating "0 - 1 < 0", which is true for any int type.

Also, it may be evaluating the expression as an int (in which case those are signed zeroes), though again I don't know if the preprocessor uses types or is more basic than that.

This explains a bit more:
https://stackoverflow.com/questions/7469915/value-vs-type-code-to-determine-if-a-variable-is-signed-or-not

Note that something that may seem obvious on familiar machines (e.g., the big-flip version, which assumes twos-complement) need not be supported by the language as such.  Notably, C supports ones-complement and other more obscure number systems, more of historical interest but they remain considerations in the standard.

P.S. It occurs to me you may've meant:
Code: [Select]
uint16_t var;
...
#if IS_SIGNED_TYPE(var)
...
which shouldn't result in a syntax error, but it seems just as wrong to test run-time variables at compile-time.  Again, I'm not sure what error this would be.

As an expression, evaluated at run time, the function would work fine though.  e.g. if(IS_SIGNED_TYPE(var)) { ...}

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Online HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1456
  • Country: gb
Re: C macro to determine if a type is signed
« Reply #4 on: November 13, 2019, 12:12:59 am »
Which doesn't mean very much -- uint16_t isn't a number.  Does it not emit a syntax error?

No, it doesn't.

I only got an error when I tried it as "#if IS_SIGNED_TYPE(unsigned int)". I forget right now what the error was - something regarding a right-parenthesis.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14309
  • Country: fr
Re: C macro to determine if a type is signed
« Reply #5 on: November 13, 2019, 12:13:10 am »
It doesn't work indeed. I get the same result with GCC for other targets.

I don't think it can really work actually. Just pass anything as the argument of the IS_SIGNED_TYPE() macro, and you'll get the same result. The cast gets simply ignored. Big surprise.

It appears the cast can't be evaluated properly at compile time inside a macro unfortunately: when the macros are processed, you are at the preprocessing stage. The preprocessor has no knowledge of C types.  At the preprocessing stage, the compiler itself is not yet doing anything.

The context in which the above macro would work is if you use it in the run-time part of your code, and not in a conditional compilation (so maybe that's exactly what the people who suggest it were doing).

Like inside a function:

Code: [Select]
typedef uint16_t MyType_t;

int SomeFunction()
{
   if (IS_SIGNED_TYPE(MyType_t))
   {
        ... Do this ...
   }
   else
   {
        ... Do that ...
   }
}

Note that even at low optimization levels, it should be just as efficient as using a conditional compilation: any test that can only be true or false at compile-time will only retain the corresponding part of the code.

That said, also note that what you wanted to do is thus not possible: you can't have a warning issued during compilation (#warning) depending on the case. Try putting #warning statements in the then and else clauses. Both will appear: the preprocessor again has no way of processing the code itself and will just spit out both warnings.

I can't think of a portable and standard way of doing this in conditional compilation directives. May be doable with the additions in C11, I'll check that and will report back if so.
« Last Edit: November 13, 2019, 12:22:03 am by SiliconWizard »
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11228
  • Country: us
    • Personal site
Re: C macro to determine if a type is signed
« Reply #6 on: November 13, 2019, 12:23:57 am »
Remember, macros are just that, macros that are expanded before compilation.
C preprocessor does expression evaluation on its own. All types are ints and all unknown symbols are turned into 0.

And yes, just use a normal "if". Any sane compiler will optimize that stuff anyway.
« Last Edit: November 13, 2019, 12:25:42 am by ataradov »
Alex
 

Online HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1456
  • Country: gb
Re: C macro to determine if a type is signed
« Reply #7 on: November 13, 2019, 12:26:00 am »
Note that even at low optimization levels, it should be just as efficient as using a conditional compilation: any test that can only be true or false at compile-time will only retain the corresponding part of the code.

Ah, I hadn't thought about a run-time check in that way - that the compiler might optimise-away the block in question. I will have to do it and look at the generated assembly. :-+

Edit: It does indeed optimise away the block of code if the type is unsigned. Great!
« Last Edit: November 13, 2019, 12:39:35 am by HwAoRrDk »
 

Offline TK

  • Super Contributor
  • ***
  • Posts: 1722
  • Country: us
  • I am a Systems Analyst who plays with Electronics
Re: C macro to determine if a type is signed
« Reply #8 on: November 13, 2019, 12:33:49 am »
Why do you need to test the signed/unsigned type during compile time if YOU are writing the code?
 

Online HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1456
  • Country: gb
Re: C macro to determine if a type is signed
« Reply #9 on: November 13, 2019, 12:41:00 am »
Why do you need to test the signed/unsigned type during compile time if YOU are writing the code?

Because I want to make it so that the only thing I have to change is a typedef to enable certain parts of the code. So basically, convenience.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14309
  • Country: fr
Re: C macro to determine if a type is signed
« Reply #10 on: November 13, 2019, 12:53:15 am »
Why do you need to test the signed/unsigned type during compile time if YOU are writing the code?

Because I want to make it so that the only thing I have to change is a typedef to enable certain parts of the code. So basically, convenience.

Ok, so this should work fine for your needs. The thing that won't, as I said, is the #warning part... but apparently, if it's just for enabling certain parts of the code, it's ok. You can do without the warning.

Anyway, I tried something with the new _Generic() construct in C11. Unfortunately, _Generic statements are NOT expanded in #if directives, so that still doesn't work for that case.
If interested for other uses, you can take a look at what you could do with _Generic though, it can be handy - dunno if AVR-GCC supports C11, but if it's based on a reasonably recent version of GCC, it should.
 

Offline TK

  • Super Contributor
  • ***
  • Posts: 1722
  • Country: us
  • I am a Systems Analyst who plays with Electronics
Re: C macro to determine if a type is signed
« Reply #11 on: November 13, 2019, 12:57:30 am »
Why do you need to test the signed/unsigned type during compile time if YOU are writing the code?

Because I want to make it so that the only thing I have to change is a typedef to enable certain parts of the code. So basically, convenience.
You can do something like this as you already know if it is signed or unsigned (assume uint* and unsigned* are unsigned, all the others signed).  I think this is 100% compiler independent.

I use unsigned when programming microcontrollers.

Code: [Select]
// Comment the next 2 lines if using unsigned
typedef int typex;
#define SIGNED 1
// Comment the next line if using signed
//typedef uint16_t typex;



#ifdef SIGNED
...
#else
...
#endif

« Last Edit: November 13, 2019, 01:01:00 am by TK »
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21609
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: C macro to determine if a type is signed
« Reply #12 on: November 13, 2019, 10:50:39 am »
Yeah, setting a flag is probably the better way.  You don't have to rely on optimizations to do it -- #if-blocks are the traditional way of enabling pieces of code.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 6733
  • Country: pl
Re: C macro to determine if a type is signed
« Reply #13 on: November 13, 2019, 12:31:02 pm »
Then you may want to add a hack to break compilation if the type is not marked as signed by mistake:

Code: [Select]
#ifndef SIGNED
int dummy[-IS_SIGNED(type)]
#endif

This forces the compiler to honestly evaluate IS_SIGNED(type) and create an array of 0 or -1 elements. The former is OK, the latter is an error.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14309
  • Country: fr
Re: C macro to determine if a type is signed
« Reply #14 on: November 13, 2019, 04:25:27 pm »
As a bonus, a simple example of how you can use _Generic in C11:

Code: [Select]
int Abs(uint16_t n)
{
return _Generic(n,
uint16_t: n,
int16_t: (n < 0)? -n : n);
}

 

Offline Brutte

  • Frequent Contributor
  • **
  • Posts: 614
Re: C macro to determine if a type is signed
« Reply #15 on: November 13, 2019, 05:57:48 pm »
You can use gcc extension __builtin_types_compatible_p which returns 1 if arguments are compatible.

 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1198
  • Country: fi
Re: C macro to determine if a type is signed
« Reply #16 on: November 13, 2019, 07:32:51 pm »
Man, just go C++ already.
 
The following users thanked this post: T3sl4co1l

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6173
  • Country: fi
    • My home page and email address
Re: C macro to determine if a type is signed
« Reply #17 on: November 13, 2019, 08:13:21 pm »
Signed overflow/undeflow handling in GCC is well defined, and all unsigned types (on architectures GCC supports) are the exact same size as their signed variants, so I'm puzzled as to what is OP's use case.

The only way I know offhand of how to handle this kind of situation, is to write a prebuild checker, that outputs the definitions for type-specific signedness macros to a generated header file; say CHAR_IS_SIGNED, MYTYPE_IS_SIGNED, and so on.  The actual source can then do  #if  CHAR_IS_SIGNED==1 et cetera.  However, this precludes cross compilation, although that can be worked around by providing handwritten variants of the generated header files.

So, what's the actual use case?  I bet there is a better solution...
 

Offline blacksheeplogic

  • Frequent Contributor
  • **
  • Posts: 532
  • Country: nz
Re: C macro to determine if a type is signed
« Reply #18 on: November 18, 2019, 06:58:07 am »
Because I want to make it so that the only thing I have to change is a typedef to enable certain parts of the code. So basically, convenience.

Pass it though as a compiler option using -D

for example:
EXTRA_CFLAGS = -DXXXX


#ifdef XXXX
   <whatever>
#endif
« Last Edit: November 18, 2019, 07:12:17 am by blacksheeplogic »
 

Offline blacksheeplogic

  • Frequent Contributor
  • **
  • Posts: 532
  • Country: nz
Re: C macro to determine if a type is signed
« Reply #19 on: November 18, 2019, 07:06:05 am »
The only way I know offhand of how to handle this kind of situation, is to write a prebuild checker, that outputs the definitions for type-specific signedness macros to a generated header file; say CHAR_IS_SIGNED, MYTYPE_IS_SIGNED, and so on.  The actual source can then do  #if  CHAR_IS_SIGNED==1 et cetera.  However, this precludes cross compilation, although that can be worked around by providing handwritten variants of the generated header files.

I don't like doing it but in the past where I've needed a pre-processing step I deal with it in the makefile:
.SUFFIXES .cx

.cx.c:
<pre-processing step>


And before you point it out, yes, that is the old school way, but I'm old and so are many of my makefiles.
« Last Edit: November 18, 2019, 07:14:56 am by blacksheeplogic »
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6173
  • Country: fi
    • My home page and email address
Re: C macro to determine if a type is signed
« Reply #20 on: November 18, 2019, 08:41:45 am »
I don't like doing it but in the past where I've needed a pre-processing step I deal with it in the makefile:
In this case, you need a test program, that when compiled and run, emits the header definitions.  I'd use something along the lines of
Code: [Select]
include/signedness.h:
        $(CC) $(CFLAGS) $(SRCDIR)/generate-signedness.c $(LDFLAGS) -o host-bin/generate-signedness$(EXESUFFIX)
        host-bin/generate-signedness$(EXESUFFIX) > $@
i.e. compile a test program with the current configuration, then run it; and have it emit the C header file with the signedness definitions.
You'll then need to list include/signedness.h as a prerequisite to the sources that refer to it.

Like I said, the downside is that when cross-compiling to another architecture,  the second step should be run on the target architecture and not locally (although the only base type whose signedness varies from architecture to architecture is char, I believe).   If the recipe is listed without prerequisites, then providing a include/signedness.h file suitable for the target architecture suffices; make won't try to regenerate it.
 

Offline golden_labels

  • Super Contributor
  • ***
  • Posts: 1183
  • Country: pl
Re: C macro to determine if a type is signed
« Reply #21 on: November 29, 2019, 07:19:37 pm »
⚠ Warning: that code hasn’t been tested in production and should be considered experimental

I wonder if that would work, if you’re caring only about required(1) built-in types for which signedness is defined or can be determined from the preprocessor(2), or about any typedef of any of those types:
Code: [Select]
// Copyright © 2019 mpan; <https://mpan.pl/>; CC0 1.0 (THIS CODE!)
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <wchar.h>

#define OVERLOAD_BY_SIGN(value, signedFn, unsignedFn) _Generic((value),\
    unsigned char: (unsignedFn),\
    unsigned short: (unsignedFn),\
    unsigned int: (unsignedFn),\
    unsigned long: (unsignedFn),\
    unsigned long long: (unsignedFn),\
    signed char: (signedFn),\
    short: (signedFn),\
    int: (signedFn),\
    long: (signedFn),\
    long long: (signedFn),\
    char: OVERLOAD_BY_SIGN_CHAR((unsignedFn), (signedFn)),\
    default: _Generic((value),\
            _Bool: (unsignedFn), default: _Generic((value),\
            size_t: (unsignedFn), default: _Generic((value),\
            ptrdiff_t: (signedFn), default: _Generic((value),\
            uintmax_t: (unsignedFn), default: _Generic((value),\
            intmax_t: (signedFn), default: _Generic((value),\
            uint_least16_t: (unsignedFn), default: _Generic((value),\
            uint_least32_t: (unsignedFn), default: _Generic((value),\
            uint_least64_t: (unsignedFn), default: _Generic((value),\
            int_least16_t: (signedFn), default: _Generic((value),\
            int_least32_t: (signedFn), default: _Generic((value),\
            int_least64_t: (signedFn), default: _Generic((value),\
            uint_fast8_t: (unsignedFn), default: _Generic((value),\
            uint_fast16_t: (unsignedFn), default: _Generic((value),\
            uint_fast32_t: (unsignedFn), default: _Generic((value),\
            uint_fast64_t: (unsignedFn), default: _Generic((value),\
            int_fast8_t: (signedFn), default: _Generic((value),\
            int_fast16_t: (signedFn), default: _Generic((value),\
            int_fast32_t: (signedFn), default: _Generic((value),\
            int_fast64_t: (signedFn), default: _Generic((value),\
            wchar_t: OVERLOAD_BY_SIGN_WCHAR((unsignedFn), (signedFn)),\
                  default: _Generic((value),\
            default: (abort)\
        )))))))))))))))))))))\
    )(value);

#if CHAR_MIN < 0
    #define OVERLOAD_BY_SIGN_CHAR(unignedFn, signedFn) (signedFn)
#else
    #define OVERLOAD_BY_SIGN_CHAR(unignedFn, signedFn) (unsignedFn)
#endif

#if WCHAR_MIN < 0
    #define OVERLOAD_BY_SIGN_WCHAR(unignedFn, signedFn) (signedFn)
#else
    #define OVERLOAD_BY_SIGN_WCHAR(unignedFn, signedFn) (unsignedFn)
#endif
Use:
Code: [Select]
#include <stdio.h>

static inline void signedCall(int const x) {
    printf("signed: %d\n", x);
}

static inline void unsignedCall(unsigned int const x) {
    printf("unsigned: %u\n", x);
}

int main(void) {
    Type x = 1;
    OVERLOAD_BY_SIGN(x, signedCall, unsignedCall);
    return 0;
}
That definition can be extended as you wish by adding yet another line to the list:
Code: [Select]
            <Type>: (<unsignedFn|signedFn>), default: _Generic((value),\A matching parenthesis must be added to the parens in the penultimate line. Unlike with plain _Generic, types can be duplicated in this structure.

The way this code works is as follows. It has two parts. The outer _Generic selector, which is really just an optimization for types that surely aren’t compatible with each other, and the inner _Generic·s sequence that performs the job for all other types. The inner _Generic·s are really a form of a linked list:
Code: [Select]
,-------.    ,-------.    ,-------.    ,-------.    ,-------.
| Type1 | ,->| Type2 | ,->| Type3 | ,->| Type4 | ,->| Type5 |
|   fn  | |  |   fn  | |  |   fn  | |  |   fn  | |  |   fn  |
|   o-----'  |   o-----'  |   o-----'  |   o-----'  |   o----> abort
`-------'    `-------'    `-------'    `-------'    `-------'
If the type of value doesn’t match the given node, it uses the default association(3), effectively going deeper into the list. The final node is using abort simply because there must be the default association there.(4) That requirement arises from the fact, that even if any “earlier” _Generic selector matches, the “later” ones still need to be valid: if the final one would not have the default association, it would be valid only for a single type, which would break the whole code.
The outer _Generic is just a plain old selector, which uses the inner one iff the type isn’t found on the list already.

Some platforms may lack things like wchar_t, so this is just a template to be adjusted as needed. It is also not completely eliminating supplying informtion from external sources during build, as described in the posts of other people here, but merely limits the amount of work to be done and streamlines access to it.

This code needs a compiler that eliminates unused static inline functions. If that requirement is not met, it will waste space in the final executable. If the compiler can do that for static functions it is even better.

Alternatively, if the final “(value)” portion of the macro definition is removed, the signedFn and unsignedFn arguments can actually be arbitrary expressions — as long as they can be used as arguments to a macro (consider putting them in parens if they contain the comma operator). The benefit is that the unused code is surely eliminated on any sane comiler and less code has to be written. The drawback is that if no type matches, the sentinel abort is a no-effect code that on some platforms may even be unreported. Consider replacing it with a call that will stop the code.
____
(1) Some compiler-specific built-in types have to be added manually, perhaps using conditional inclusion.
(2) E.g. time_t signedness can’t be determined.
(3) 6.5.1.1§2
(4) 6.5.1.1§2–3
People imagine AI as T1000. What we got so far is glorified T9.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4068
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: C macro to determine if a type is signed
« Reply #22 on: November 29, 2019, 08:42:42 pm »
Someone posted a solution right here. But removed it!
Anyway, it doesn't use the preprocessor, but it seems to works compile time just fine. On all GNU derived compilers. It doesn't work in msvc.

See here: https://godbolt.org/z/k3JC65

It only generates mov and call assembly stating.

Due to it not working in msvc should be an indicator that you're entering terrain that will need to carry ifdefs and erroring out on unknown compilers. Not very useful.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6173
  • Country: fi
    • My home page and email address
Re: C macro to determine if a type is signed
« Reply #23 on: November 29, 2019, 09:38:04 pm »
If you want a runtime check, then I recommend using
Code: [Select]
#define  IS_SIGNED_TYPE(type) ( (type)(-1) < (type)(0) )
which relies on C99 or later (and thus C++) casting rules: a cast to any numeric type restricts the value to the precision and range of the type.  This should work fine even on MSVC.  If -O1 or better optimizations are enabled, gcc and other compilers should optimize the code to no-op.

Here's an example program:
Code: [Select]
#include <stdlib.h>
#include <stdio.h>

#define  IS_SIGNED_TYPE(type) ( (type)(-1) < (type)(0) )

int main(void)
{
    printf("char is %s\n", IS_SIGNED_TYPE(char) ? "signed" : "unsigned");
    printf("unsigned char is %s\n", IS_SIGNED_TYPE(unsigned char) ? "signed" : "unsigned");
    printf("signed char is %s\n", IS_SIGNED_TYPE(signed char) ? "signed" : "unsigned");
    printf("float is %s\n", IS_SIGNED_TYPE(float) ? "signed" : "unsigned");
    printf("long long int is %s\n", IS_SIGNED_TYPE(long long int) ? "signed" : "unsigned");
    printf("unsigned long long int is %s\n", IS_SIGNED_TYPE(unsigned long long int) ? "signed" : "unsigned");
    return EXIT_SUCCESS;
}

However, this is not a solution that can be utilized in the preprocessor, and that's what OP stated they needed.
« Last Edit: November 29, 2019, 09:40:05 pm by Nominal Animal »
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6173
  • Country: fi
    • My home page and email address
Re: C macro to determine if a type is signed
« Reply #24 on: November 29, 2019, 10:21:04 pm »
As I explained before, it is possible to compile and run at build time a program that generates the necessary macros for the types needed.
The downside is that this won't work when cross-compiling to a different architecture or OS.

Let's say you have in your Makefile (simplified, with build and source directories the same),
Code: [Select]
signedness.h: generate-signedness
    $(CC) $(CFLAGS) -o generate-signedness generate-signedness.c
    ./generate-signedness > $@

generate-signedness: generate-signedness.c
    $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@

%.o: %.c signedness.h
    $(CC) $(CFLAGS) -c $< -o $@

yourprog: list of object files
    $(LD) $(LDFLAGS) $^ -o $@
with generate-signedness.c containing
Code: [Select]
#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>

#define  IS_SIGNED_TYPE(type) ( (type)(-1) < (type)(0) )

#define  DEFINE(type)  do { printf("#define type_" #type "_is_signed %d\n", IS_SIGNED_TYPE(type)); } while (0)

int main(void)
{
    DEFINE(char);
    DEFINE(size_t);   
    DEFINE(time_t);
    DEFINE(off_t);

    printf("#define JOIN3(a,b,c) a##b##c\n");
    printf("#define is_signed_type(type) JOIN3(type_, type, is_signed)\n");

    return EXIT_SUCCESS;
}
with a DEFINE(type) line for each type the code might be interested in.

Then, in any of the other C source files,
Code: [Select]
#include "signedness.h"

#if is_signed_type(time_t)
    /* time_t is a signed type */
#else
    /* time_t is an unsigned type */
#endif

#if is_signed_type(char)
    /* char is a signed type */
#else
    /* char is an unsigned type */
#endif

When cross-compiling such code, one can provide the signedness.h file as-is.  When it exists, it will not be regenerated/replaced.

Now, looking at the actual code above, I'd probably instead keep pregenerated signedness.h files in a subdirectory, with a special target to regenerate one for the current host system, and instead detect the current OS using $(OS) (and $(shell uname -s) on non-Windows systems), and architecture using $(PROCESSOR_ARCHITECTURE) and $(PROCESSOR_ARCHITEW6432) on Windows and $(shell uname -p) on all other systems, copying the correct header file to the build directory.
« Last Edit: November 29, 2019, 10:24:34 pm by Nominal Animal »
 

Offline golden_labels

  • Super Contributor
  • ***
  • Posts: 1183
  • Country: pl
Re: C macro to determine if a type is signed
« Reply #25 on: November 29, 2019, 10:46:17 pm »
Due to it not working in msvc should be an indicator that you're entering terrain that will need to carry ifdefs and erroring out on unknown compilers. Not very useful.
C is not really supported by MSVC, so it is not expected that any C code will work there. Nowadays MSVC is a Microsoft C++/CLI compiler, which can also handle C++(1). C is “supported” only as long as it more or less falls under what C++ covers.
____
(1) But I heard it may fail to reject invalid C++ code despite required to do so.
People imagine AI as T1000. What we got so far is glorified T9.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4068
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: C macro to determine if a type is signed
« Reply #26 on: November 29, 2019, 10:59:29 pm »
As I explained before, it is possible to compile and run at build time a program that generates the necessary macros for the types needed.
The downside is that this won't work when cross-compiling to a different architecture or OS.
I have written a code generator in python for some C project. It fills a linked-list from snippets defined in many files. You could go this route.
There is even a C parser (compiled C) for python if you want.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6173
  • Country: fi
    • My home page and email address
Re: C macro to determine if a type is signed
« Reply #27 on: November 30, 2019, 01:47:03 am »
As I explained before, it is possible to compile and run at build time a program that generates the necessary macros for the types needed.
The downside is that this won't work when cross-compiling to a different architecture or OS.
I have written a code generator in python for some C project. It fills a linked-list from snippets defined in many files. You could go this route.
There is even a C parser (compiled C) for python if you want.
No, the issue is that the C code must be compiled and run on the target OS and architecture, not on the host, to determine the signedness.  You cannot determine the signedness of arbitrary types on the target by doing stuff on the host.  Having a code generator does not help at all there.

As to the types whose signedness is needed, that is trivial to maintain, and does not need a code generator: consider the practical use cases.
« Last Edit: November 30, 2019, 06:36:32 pm by Nominal Animal »
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: C macro to determine if a type is signed
« Reply #28 on: November 30, 2019, 12:48:04 pm »
Someone posted a solution right here. But removed it!

It was probably me. I didn't like the solution as it was *really* an ugly hack, and requires manual maintenance etc. Also, it won't work with something like
Code: [Select]
IS_SIGNED(unsigned int) /* Will not work */
However, here is the principle:

Code: [Select]
#define char_is_signed 1
#define int_is_signed 1
#define int8_t_is_signed 1
#define uint8_t_is_signed 0
#define int16_t_is_signed 1
#define uint16_t_is_signed 0
#define int32_t_is_signed 1
#define uint32_t_is_signed 0

#define IS_SIGNED(T) (T ## _is_signed)
« Last Edit: November 30, 2019, 03:23:15 pm by Kalvin »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf