question about basic C standard for operators

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

Hi, guys,

I just found out a bug in my code was due to my misunderstanding of operation result in C.

So then I'm wondering if the following assumption of mine is correct:

the binary operators, like +, -, * and /, their operation result will be a promoted value compared with their operand. Say:
A and B are uint8, so the result of A - B would be saved as uint16 in registers, right?

the singular operators, like ^, ~, ++, --, >> and <<, their operation result will still have the class. Say:
A is uint16, so ^A will still be a uint16, right?

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

when you say "saved as unit16 in registers" are you talking about intermediate results in a calculation or the final result? The final result will be promoted/truncated to the type of the destination so that:

	uint8_t a;
	uint16_t b=12345, c=23456;

	a = b + c;

Gives a=217. The result (12345+23456) is actually 0x8BD9 but the 0x8B is lost leaving 0xD9 in 'a' which is 217.

Oh and if you have 'x' and 'y' that are both uint8_t then x-y will be a uint8_t result as well but if you assign z=x-y and z is uint16_t:

	uint8_t x=17, y=51;
	uint16_t z;

	z = x - y;

Then z ends up holding 0xFFDE. The result of 17-51 in 8 bits is 0xDE but assigned to a uint16_t this is sign extended to become 0xFFDE

Cliff

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

hehe, sorry, I mean the intermediate value, cos in my case, the bug code was:

uint8 a,b;
...
...
if ((a - b) == 1)
{
...
}

when a is 0x00 and b is 0xFF, the intermediate result of (a - b) was 0xFF01, so it != 1
then I typecast to my new code:

uint8 a,b;
...
...
if ((unsigned char)(a - b) == 1)
{
...
}

then the code works

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

It's a dodgy practice to be using unsigned variables for doing signed mathematics in the first place isn't it? The result of 0-255 is -255 - it's never 1 unless, as you say, you take the the internal 0xFF01 or 0xFFFFFF01 (or whatever) representation and drop the sign bits. The "official" way to drop sign bits is to use abs() (which returns the absolute value). I'd suggest:

if (abs(a-b) == 255) {

which will be true when 'a' is zero and 'b' is 255

Cliff

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

the reason I use this uint8 was because it's the packet number of Xmodem-CRC packet, and when it overflows, it jumps from 0xFF to 0x00, so I have a variable to save this value and to compare with the next packet number, so this is why I use this way.

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

abs() of unsigned entities isn't correct.

re this, for unsigned bytes
"the result of 0-255 is -255"

I disagree with. The result is 255, not -255, since the result cannot change types unless you cast it.

For me, thinking of C as a portable assembly language is better than thinking of it as a high level language. So when you code like this using unsigned types, just think of what the microprocessor itself would do, not the compiler.

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

yes, stevech, you are right

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

darthvader wrote:
the reason I use this uint8 was because it's the packet number of Xmodem-CRC packet, and when it overflows, it jumps from 0xFF to 0x00, so I have a variable to save this value and to compare with the next packet number, so this is why I use this way.

Heh, I am also working on something that might have xmodem in it. Also I'd like to thank darthvader to ask the question which I answered that the file should be patched to 128 byte packets instead of letting the xmodem protocol to do it. It gave me a great idea for my master's thesis.

But anyway, simplest way of knowing the next packet number, which includes the overflowing, is just unsigned 8 bit number, as it will overflow from 0xff to 0x00.


uint8_t xmodem_num;
uint8_t expected_num;

...

expected_num = 1; // first packet in a transmission 

...

xmodem_num=usart_read();

...

if (xmodem_num == expected_num)
{
    expected_num++; // this will overflow from 0xff to 0x00

    process_packet();

}
else
{
    send_nak(); // request same packet again to get expected number
}

...

- Jani

EDIT: Also if you want to check the inverted xmodem packet number, you should receive that as uint8_t and compare it with uint8_t to be a value of (255-expected_num). Or you can initialize some uint8_t expected_inverted = 0xfe and decrease it every time you increase the packet number too, as that will then underflow from 0x00 to 0xff.

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

Hi, Jani,

What's the serial terminal software you are using now?

I'm using TeraTerm.

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

darthvader wrote:
Hi, Jani,

What's the serial terminal software you are using now?

I'm using TeraTerm.

Hi darthvader,

I have not done any actual xmodem data transfer between an AVR and PC yet, so I am not using any terminal software for that right now. But as one can guess, a bootloader is on the works. And the micro is not AVR, so please don't blame me as an infidel =)

I did experiment with RealTerm and HyperTerm, after connecting 2 serial ports in a PC with a null-modem cable. I watched packets flowing and stuff, for testing my ideas. Hyperterm talked xmodem packets, RealTerm talked hexadecimal numbers. Experimented with uploads and downloads, regular xmodem and xmodem-crc.

If you have troubles using the xmodem protocol, check out Atmels application note about how to do xmodem with AVRs. And while you are at it, learn to use CRC for error detection.

Btw, what do you do with this info?

- Jani

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

what info?
I just implemented the Xmodem by application note AVR350

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

I mean, why did you ask what terminal software I use? Are you having trouble with TeraTerm?

- Jani

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

Yes, TeraTerm has some small problems in Xmodem file transmission.