SOLVED: Any way to test if a variable is signed or not?

Hi all,

I’m trying to write a “universal” function using [b]template <class T>[/b] and I need to be able to determine if “T” is signed or unsigned at runtime.

I Googled a bunch of different things and can’t seem to find anything.

What I basically need is something like this:

if (typeof (T) == "unsigned") {
    do_this ();
} else {
    do_that ();
}

Any help will be appreciated!

P.S. This is in C++, not C or C#.

Your limited research should have found that ALL numeric variables are positive signed unless explicitly signe negative.

Paul

template<typename _Tp>
struct is_signed
{
  static bool const value = _Tp(-1) < _Tp(0);
};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println(is_signed<int>::value);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Untested, but adapted from the STL type_traits header. Actually quite ingenious.

Paul_KD7HB:
Your limited research should have found that ALL numeric variables are positive signed unless explicitly signe negative.

Paul

I don’t understand the relevance of this response to the post. Anyone can look at the code and see whether the variable type is signed or (explicitly) unsigned. OP was asking how to do that from the code.

Krupski:
I’m trying to write a “universal” function using [b]template <class T>[/b] and I need to be able to determine if “T” is signed or unsigned at runtime.

On a second reading, you might be confused. Templates do not work at run time, only at compile time because that is when types are defined.

At least, I’m confused. What application do you want to put this function towards?

Paul_KD7HB:
Your limited research should have found that ALL numeric variables are positive signed unless explicitly signe negative.

Paul

No, what I mean is that I will pass a value (in a variable) to a function and I need to determine if the passed variable was signed or unsigned.

To clarify:

uint8_t value = 10;
my_func (value);
// my_func determines that the passed var is unsigned

int newval = -25;
my_func (newval);
// my_func determines that the passed var is signed

That's what I'm after.

Jiggy-Ninja:

template<typename _Tp>

struct is_signed
{
 static bool const value = _Tp(-1) < _Tp(0);
};

void setup() {
 // put your setup code here, to run once:
 Serial.begin(9600);
 Serial.println(is_signed::value);
}

void loop() {
 // put your main code here, to run repeatedly:

}



Untested, but adapted from the STL **type_traits** header. Actually quite ingenious.

Clever! I’ll try it… I’ll bet it works. I can make it into a macro (like #define is_signed(V)…blah).

I’ll let you know if it works. Thanks and a karma++ for you.

Jiggy-Ninja:
On a second reading, you might be confused. Templates do not work at run time, only at compile time because that is when types are defined.

At least, I’m confused. What application do you want to put this function towards?

Here’s an example of a piece of code in my DS3234 driver library that reads the battery backed SRAM:

// read from RTC BSRAM any data type
template <class T> T DS3234::_readAll (uint8_t address, T &value)
{
    uint8_t x = sizeof (value);
    uint8_t *ptr = (uint8_t *) (void *) &value;

    while (x--) {
        _command ((RADR | WR), address + x);
        *(ptr + x) = _command ((RDAT | RD), 0);
    }

    return value;
}

In this function, all I need to know is how many bytes to read to satisfy the variable type.
In the function that I’m asking the question about, I ALSO need to know if the passed variable is signed or unsigned. The reason is this: Let’s say I take a [b]uint8_t[/b] with a value of 255 and pass it. Should my function consider it to be 255, or -1?

Krupski:
Clever! I’ll try it… I’ll bet it works. I can make it into a macro (like #define is_signed(V)…blah).

I’ll let you know if it works. Thanks and a karma++ for you.

There’s a ton more stuff in there, some of it really clever using inheritance from helper classes and partial specialization.

Like is_const (going from memory):

template<class T>
struct is_const
{
  static const bool value = false;
};

template<class T>
struct is_const<T const>
{
  static const bool value = true;
};

I’ve attached the type_traits header that came with my desktop C++ IDE. You’ll see that I’ve simplified their implementation quite a bit in porting it.

Check it all out.

type_traits.h (62.7 KB)

Jiggy-Ninja:
There’s a ton more stuff in there, some of it really clever using inheritance from helper classes and partial specialization.

Like is_const (going from memory):

template<class T>

struct is_const
{
 static const bool value = false;
};

template
struct is_const
{
 static const bool value = true;
};



I've attached the type_traits header that came with my desktop C++ IDE. You'll see that I've simplified their implementation quite a bit in porting it.

[Check it all out.](http://www.cplusplus.com/reference/type_traits/)

OK, I looked at it and honestly didn’t understand how to use it. Also, I would like (although not absolutely necessary) for it to work in C and C++.

Anyway, an idea popped into my head, I tried it and it seemed to work. Then I expanded the test and it didn’t work reliably. See what you think and why it “sort-of” works, but not all of it:

First of all, I tried this macro: [b]#define IS_SIGNED(T)(T=-1,T==-1?1:0)[/b]

#define IS_SIGNED(T)(T=-1,T==-1?1:0)

int main (void)
{
    char buffer [64];

    uint8_t u8;
    int8_t s8;
    uint16_t u16;
    int16_t s16;
    signed int si;
    unsigned int ui;

    init();
    Serial.begin (115200);

    sprintf (buffer, "u8 is %s\n", IS_SIGNED (u8) ? "signed" : "unsigned");
    Serial.print (buffer);
    sprintf (buffer, "s8 is %s\n", IS_SIGNED (s8) ? "signed" : "unsigned");
    Serial.print (buffer);
    sprintf (buffer, "u16 is %s\n", IS_SIGNED (u16) ? "signed" : "unsigned");
    Serial.print (buffer);
    sprintf (buffer, "s16 is %s\n", IS_SIGNED (s16) ? "signed" : "unsigned");
    Serial.print (buffer);
    sprintf (buffer, "si is %s\n", IS_SIGNED (si) ? "signed" : "unsigned");
    Serial.print (buffer);
    sprintf (buffer, "ui is %s\n", IS_SIGNED (ui) ? "signed" : "unsigned");
    Serial.print (buffer);

    while (1);
}

And this is what it outputs:

[b]u8 is unsigned
s8 is signed
[color=red]u16 is signed[/color]
s16 is signed
si is signed
[color=red]ui is signed[/color][/b]

The ones I highlighted in red are wrong!!! Why on earth would uint8_t work but the other unsigned ones fail? ARGHHHHHH!!!

It’ll work with this:

#define IS_SIGNED(T)(T=-1,T < 0?1:0)

Pete

el_supremo:
It’ll work with this:

#define IS_SIGNED(T)(T=-1,T < 0?1:0)

Pete

I just discovered that here!!! Don’t even need the ternary operator. This works:

[b]#define IS_SIGNED(T)(T=-1,T<0)[/b]

Yippee!!!

The result of the test program:

[b]
(should be unsigned) u8 is unsigned
(should be unsigned) u16 is unsigned
(should be unsigned) ui is unsigned
(should be signed) s8 is signed
(should be signed) s16 is signed
(should be signed) si is signed[/b]

Funny thing is, it even correctly returns “signed” if I pass it a float or double! :slight_smile:

P.S. karma++ for you.

Thanks.

Pete

Also, I would like (although not absolutely necessary) for it to work in C

I'm curious how you plan to use templates in C.

That macro will modify the value of the variable you pass as T. That’s fine if you’re OK with it, but there’s a better way to do it if you want C compatibility.

#define IS_SIGNED(T) ((T)-1 < (T)0)

You need to pass a typename as T. If you want to use a variable name you need to use the typeof() operator.

	unsigned long d;
	cout << IS_SIGNED(typeof(d));

Jiggy-Ninja:
That macro will modify the value of the variable you pass as T. That’s fine if you’re OK with it, but there’s a better way to do it if you want C compatibility.

#define IS_SIGNED(T) ((T)-1 < (T)0)

You need to pass a typename as T. If you want to use a variable name you need to use the typeof() operator.

	unsigned long d;
cout << IS_SIGNED(typeof(d));

Yeah, I discovered that when testing it more completely! :slight_smile:

Tha t won’t work because I won’t know what type of var is being passed. But anyway, I came up with the “blue” solution tinkering with it, so now my function is working like I wanted it to.

By the way, was it you that I was earlier discussing problems reading EEPROM words with an ATTiny85?

If so, you may recall that I came up with a kludge solution to the problem, but my solution only worked with integers. Well, I modified the functions so that they work with any variable type (including float and double).

FYI, here they are:

// universal eeprom READ (for EEMEM, not EEPROM library stuff)
template <class T> T eepromRead (const T *addr)
{
    uint8_t x = sizeof (T);
    T value;
    uint8_t *ptr = (uint8_t *)(void *)&value;

    while (x--) {
        *(ptr + x) = (eeprom_read_byte ((uint8_t *)(addr) + x));
    }

    return value;
}

// universal eeprom WRITE (for EEMEM, not EEPROM library stuff)
template <class T> void eepromWrite (T *addr, T value)
{
    uint8_t x = sizeof (T);
    uint8_t *ptr = (uint8_t *)(void *)&value;

    while (x--) {
        eeprom_write_byte ((uint8_t *)(addr) + x, *(ptr + x));
    }
}

Instead of just OR’ing in bytes, I instead grab the byte sized data in the variable and read or write it. Works great.

At first it wouldn’t work and I looked at it and looked at it and could see nothing wrong. Then I kicked myself in the behind… I had forgotten to take out the “var << 8” stuff! Don’t need that any longer.

Thanks again for your help with this “typeof” problem!

Krupski:
Tha t won't work because I won't know what type of var is being passed.

That's why I said to use the typeof() operator. You use it like sizeof(), except instead of returning the size of a variable it returns the type. Check the second snippet of code I posted.

By the way, was it you that I was earlier discussing problems reading EEPROM words with an ATTiny85?

Sounds familiar. Good to know you found the problem.