Listing of data types for AVR-GCC?

Go To Last Post
24 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi - I've been trying to find a list of the data types for AVR-GCC and their associated bit lengths, but I just can't. Can anybody point me in the right direction? Thanks!

edit: I might as well bring up the code that is causing me issues:

servotimer[1] = travelstart[1] + ((signed long)(travelcounter[1] * traveltotal[1]))/travelsteps[1];

where servotimer is an unsigned int, travelstart is an unsigned int, travelcounter is an unsigned char, traveltotal is a signed int, and travelsteps is an unsigned char. I'm getting wierd output from this line of code, and I believe somehow the data type is getting overloaded - but with an int being only 16b, I don't see how it's possible that multiplying it by an 8b char would overload a 32b data type.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try:

servotimer[1] = travelstart[1] + ((signed long)travelcounter[1] * traveltotal[1])/travelsteps[1]; 

The expression (travelcounter[1] * traveltotal[1]) is computed as a signed int (the biggest type in that expression). The fact that you then cast the result to a signed long does not help, it is too late.

Edit: About the types available, just use the types from (uint8_t, uint16_t etc).

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lajon wrote:
Try:

servotimer[1] = travelstart[1] + ((signed long)travelcounter[1] * traveltotal[1])/travelsteps[1]; 

The expression (travelcounter[1] * traveltotal[1]) is computed as a signed int (the biggest type in that expression). The fact that you then cast the result to a signed long does not help, it is too late.

Edit: About the types available, just use the types from (uint8_t, uint16_t etc).

/Lars


Hi Lars - that worked perfectly. Just a note of clarification: In C, when arithmetic is done, all variables are brought up to the largest type in the expression, correct?

Also - my original question still stands - does anybody know where a list of the data types that AVR-GCC supports is?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, C promotes operands to the size of the largest operand in the calculation - for example multiplying a long by a char would promote the char to a long.

GCC supports the following datatypes:

Quote:
(signed/unsigned) char - 1 byte
(signed/unsigned) short - 2 bytes
(signed/unsigned) int - 2 bytes
(signed/unsigned) long - 4 bytes
(signed/unsigned) long long - 8 bytes
float - 4 bytes (floating point)
double - alias to float

I suggest you get used to the alternate datatypes outlined in the C99 standard, and made avaliable to GCC. These use the convention of a "u" to denote the signedness (no "u" to denote signed), "int" to denote that it's a integer and not a float, the number of bits in the int and a trailing "_t". Examples:

int8_t - Signed Char
uint16_t - Unsigned Int
uint32_t - Unsigned Long
int64_t - Signed Long Long

Etc, etc. The advantage to using these names is that those bit sizes are guaranteed to remain the same across platforms and compilers, so you get added code portability.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could someone explain to me why you would want to take a 32 bit number add an 8 bit number to it and then represent it by a 16 bit variable (servotimer[1])?

Just curious.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
why you can would

Is that why you can, why you could, or how can you?! Assuming the latter, casts are your friend.

16BitVar = (unint16_t)(32BitVar + 8BitVar); // Automatic promotion of 8BitVar to a uint32_t

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like I did not edit the post correctly or you got it before I corrected it!

Could someone explain to me why you would want to take a 32 bit number add an 8 bit number to it and then represent it by a 16 bit variable (servotimer[1])?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

davef wrote:
Looks like I did not edit the post correctly or you got it before I corrected it!

Could someone explain to me why you would want to take a 32 bit number add an 8 bit number to it and then represent it by a 16 bit variable (servotimer[1])?


That line of code is a crucial line for a servo controller I'm working on. Specifically, that line controls the travel function, which allows me to tell it to go from one angle to another in a certain period of time. Very useful for my purposes (6-legged robot)

servotimer[] holds values to write into OCR1B that sets the length of the PWM pulse for a hobby servo. When the travel function is turned on, travelstart[] is loaded with the OCR1B value for the initial angle. Travelsteps contains the total number of steps that it will take (by using a char for that I limit the number of steps to a max of 255). Travelcounter is initially 0 but after each servo pulse (at 50hz) it is incremented. Traveltotal is the total change in OCR1B that needs to happen over the time period. So essentially what is happening is it's travelstart + (travelcounter/travelsteps) * travelcounter.

And you'll find that travelstart is an int, so it's actually adding an int to a long, I believe (that is making the assumption that after the multiply travelsteps is being brought up to being a long, so then the result of that division is a long)

Does that answer your question?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
Yes, C promotes operands to the size of the largest operand in the calculation - for example multiplying a long by a char would promote the char to a long.

GCC supports the following datatypes:

Quote:
(signed/unsigned) char - 1 byte
(signed/unsigned) short - 2 bytes
(signed/unsigned) int - 2 bytes
(signed/unsigned) long - 4 bytes
(signed/unsigned) long long - 8 bytes
float - 4 bytes (floating point)
double - alias to float

I suggest you get used to the alternate datatypes outlined in the C99 standard, and made avaliable to GCC. These use the convention of a "u" to denote the signedness (no "u" to denote signed), "int" to denote that it's a integer and not a float, the number of bits in the int and a trailing "_t". Examples:

int8_t - Signed Char
uint16_t - Unsigned Int
uint32_t - Unsigned Long
int64_t - Signed Long Long

Etc, etc. The advantage to using these names is that those bit sizes are guaranteed to remain the same across platforms and compilers, so you get added code portability.

- Dean :twisted:


Great - that's what I was looking for. Can you tell me, what do you mean by double is alias to float? Is a double just a more precise float like it is in more normal C?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You usually expect floating point variables to be in IEE754 format and for "float" to be held in 4 bytes/32 bits while "double" are 8bytes/64 bits and therefore offer far more accuracy.

But in GCC for the AVR both double and float are exactly the same thing - 4byte/32bits

Cliff

PS As usual the desciption on Wikipedia is really good - http://en.wikipedia.org/wiki/IEE...

Last Edited: Mon. Jun 5, 2006 - 04:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Double is exactly the same thing as float in avr-gcc. Anywhere the compiler sees "double", it says to itself, "Aha! The puny human said double. But I know better, so I'll replace it with float. Muwahahaha!"

And a float in avr-gcc is an IEEE754 single-precision real number in 32 bits.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

nleachcim,

> travelstart is an int
. . . my mistake, but not relevant

If you represent a 32 bit result with a 16 bit data type don't you lose the top 16 bits?

Maybe the result of the maths never is more than what can be represented by a 16 bit data type then why use a 32 bit data type for servotimer[]?

I'm relatively new to C programming, so interested why one would want to do this.

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are computing an integer expression, you need to worry about the intermediate product terms temporarily getting bigger than the int will hold... 32767... thats not too hard to do... so if you cast ONE TERM to long, the expression evaluator says 'Aha! A long! I need to evaluate this whole expression with longs!' And it does so. Usually you are evaluating volts in 'thousandths of a volt' as an integer, and everything is multiplied by 1000, or feet in hundredths, etc.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner,

Thanks for the reply. I understand more clearly now, the need to use 32 bits as an intermediate data type.

However, when if comes to placing the 32 bit result into a smaller data type I understand one has to be be very careful, ie mask off the high bits and then cast to an unsigned int . . . in this case.

servotimer[] = (uint16_t) (0x0000FFFF & 32 bit result);

The lack of casting to the smaller type is what, I think, concerned me about the original expression. Or, would you consider the above code fragment a bit "over the top"?

Cheers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'd just used the cast and be done with it -- I'd think that the explicit cast is obvious enough without requiring an unnecessary masking of the bits. Purely personal opinion though, unless the compiler does generate code for that mask...

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
unless the compiler does generate code for that mask...

Just checked and even with -O0 it doesn't. It just generates instructions to access the lower half of the uint32_t

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Data type float is sometimes called "single-precision floating point". Data type double has twice as many bits and is sometimes called "double-precision floating point".

How float is an alias to double ?

I am living to bring up new earth ,and not to eat and destroy earth.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AVR gcc doesn't support a 64-bit floating point type

so a double is treated the same as a float.

 

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

..and 13 years later on...

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Read the actual words of the C standard about float an double. It does not imply that "double" actually has to be double the width of float. For avr-gcc it isn't, both are 32 bit and thus have about 7.5 digits of digital precision.

 

In case the code you write is ever ported to other architectures it would be unwise to simply use them as synonyms. If you do this then anything "double" with have subtly different behaviour on an architecture that has a higher width. therefore the "safe" option for avr-gcc is to stick to "float" for everything. 

 

For example:

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin>.\avr-gcc -E -dM - < NUL | grep _DIG
#define __DBL_DIG__ 6
#define __DECIMAL_DIG__ 9
#define __FLT_MANT_DIG__ 24
#define __DEC64_MANT_DIG__ 16
#define __LDBL_MANT_DIG__ 24
#define __FLT_DIG__ 6
#define __DBL_MANT_DIG__ 24
#define __DBL_DECIMAL_DIG__ 9
#define __DEC32_MANT_DIG__ 7
#define __DEC128_MANT_DIG__ 34
#define __LDBL_DIG__ 6
#define __FLT_DECIMAL_DIG__ 9

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin>.\avr-gcc -E -dM - < NUL | grep _MAX_10
#define __FLT_MAX_10_EXP__ 38
#define __LDBL_MAX_10_EXP__ 38
#define __DBL_MAX_10_EXP__ 38

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin>.\avr-gcc -E -dM - < NUL | grep _MIN_10
#define __DBL_MIN_10_EXP__ (-37)
#define __FLT_MIN_10_EXP__ (-37)
#define __LDBL_MIN_10_EXP__ (-37)

Note that FLT_ and DBL_ values are the same. (actually "long double" too!)

Last Edited: Tue. Feb 5, 2019 - 09:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Read the actual words of the C standard about float an double. It does not imply that "double" actually has to be double the width of float.
It does require more than 24 bits of precision and more than 8 bits of exponent.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:

..and 13 years later on...

 

Actually, something did change in the meantime. Since version 4.7 (from 2012), avr-gcc supports 24 bit integer types (__int24 and __uint24).

They are useful for optimization sometimes. After all, AVRs are 8 bit MCUs and from that on, any extra 8 bits increments are costly.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AVR GCC 4.7 added XMEGA which has 24 bit addresses within the DMA controller's DMA channels (multiple) (DMA channel : SRCADDR, DESTADDR)

 

GCC 4.7 Release Series — Changes, New Features, and Fixes - GNU Project - Free Software Foundation (FSF)

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh, so that's why they added the 24 bit type. Still, it's useful in several situations where 16 bit is not enough but 32 bits is overkill.