warning: cast to pointer from integer of different size

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

The code below generates this warning:

Quote:

warning: cast to pointer from integer of different size

and I don't really understand why.
Can somebody please explain why?
The offending line is "Content = *((uint8_t*)Reg);

static uint8_t HandlePacket(TPacket *pMsg)
{
	char *pCursor;
	uint8_t Content;
	uint8_t Reg;

 ... 

	switch( *pCursor)
	{
	case '>':
		pCursor++;
		switch( *pCursor)
		{
		case 'r':
			MsgOut.Data[0] = 'r';
			pCursor++;
			Reg = GetUint32( &pCursor, 6 );
			ItoaF( MsgOut.Data + 1, Reg, 4, 16);
			MsgOut.Data[5] = '=';

			// Reg is a number.
			// Cast it into a pointer to a register adress.
			// Take the contents of that register.
			// Cast the contents of that register to a uint8_t.
			Content = *((uint8_t*)Reg);
			ItoaF( MsgOut.Data + 6, Content, 4, 16);	// Implicit uint8_t to uint32_t conversion.
			PacketSize = 10;
			break;
		}
		break;

A bit more background information:
Using: avr-gcc (GCC) 4.5.3
This code is meant for debugging.
My intent is to send an ascii string packed in a network packet (over uart/rs485). The avr decode's de commands and executes them en encodes the result again in another ascii string. Not the most efficient way of debugging, but most of the code already was in my project.

If I request the contents of 0x4c (TCNT1L) I get a different value each time, but the contents of the temporary register 0x4d (TCNT1H) only change after I've read TCNT1L. Other registers also seem to have plausible values.

Is this a search in the right direction?

Quote:
paul@dualcore /usr/lib/avr/include/avr $ grep -nR "define _SFR_IO8" *.h
iom128rfa1.h:54:# define _SFR_IO8_STRUCT(io_addr,type) _MMIO_BYTE_STRUCT((io_addr) + 0x20, type)
sfr_defs.h:152:#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)
sfr_defs.h:179:#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

The compiler is telling you that you told it to do something strange.
The compiler is doing it anyway.
From your comments, the compiler is doing exactly what you want.
If silencing the warning is important, cast to uint16_t before casting to pointer.

"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

While this code has Lots of Irritating Superfluous Parentheses it does make the compiler stop complaining.

Content = *((uint8_t*)((uint16_t)Reg));

Thanks Michael.


This is better:

	uint16_t Reg;
	Content = *(uint8_t*)Reg;

But for me the strange part is that the compiler wants uint16_t for an 8-bit register in an 8-bit processor.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

Last Edited: Tue. Jan 15, 2013 - 11:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pointers are 16 bits wirde but you are using a 32-bit value like a pointer. That's worth a warning because 16 bits will be lost.

avrfreaks does not support Opera. Profile inactive.

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

Quote:
... but you are using a 32-bit value like a pointer.
Where? The only 32 bit value is the implicit "upgrade" in the function call and that line does not generate the warning.

P.S. How do I add [Solved in 48 minutes] to the title?
Maybe the title is a bit to long.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

Other way round: Reg is only 8 bits. That does not comprise a sensible pointer. Sorry for misreading, got confused by the GetUint32.

avrfreaks does not support Opera. Profile inactive.

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

And what does GetUint32() return? If it really returns a pointer, then why is not Reg defined as a pointer?

Regards,
Steve A.

The Board helps those that help themselves.

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

Paulvdh wrote:
This is better:

	uint16_t Reg;
	Content = *(uint8_t*)Reg;

'Tain't.
To possibly be better, there should be a comment to the effect that you altered the type of an 8-bit variable to inhibit a warning.
Without such a comment, your successors, e.g. yourself, might be confused.

"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

Pointers in avr-gcc being 16-bit is one thing; this

Paulvdh wrote:
If I request the contents of 0x4c (TCNT1L) I get a different value each time, but the contents of the temporary register 0x4d (TCNT1H) only change after I've read TCNT1L.
is another: there are 16-bit SFRs in AVR which are to be read out bytewise in a specific order. There is an intermediate (directly unaccessible) register involved. Read thoroughly the relevant parts of manual to avoid surprises.

JW

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

GetUint32() returns an uint32_t :D

// Read a string of ascii characters, anaylse base
// convert into an integer, update the cursor.
static uint32_t GetUint32(char **Buf, uint8_t Length )

@wek / JW.
I know about the 16 -bit register stuff. In fact this behavior was for me a confirmation that I was accessing a 16 bit register of a timer with my pointer and casting stuff.

I think you can do some tricks with this.

    49:ThreadPulse.c **** TCNT1 = OCR1A; 174 .LM11:
    175 0044 8AB5 in r24,74-32
    176 0046 9BB5 in r25,74+1-32
    177 0048 9DBD out 76+1-32,r25
    178 004a 8CBD out 76-32,r24
This generates 4 opcodes, but I think it can be done with 2 because the two opcodes in the middle use the same tmp register for the same value.

@skeeve

Quote:
'Tain't.
To possibly be better...
I'll think about it and look at the listing for what the compiler does those extra 8 bits.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

Quote:

This generates 4 opcodes, but I think it can be done with 2 because the two opcodes in the middle use the same tmp register for the same value.

What are you talking about? To transfer two bytes from one place to another is always going to be two byte reads and two byte writes. That's 4 opcodes in AVR(8) land.

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

Read OCR1AL and OCR1AH is copied into the temp register.
Write TCNT1L and the temp register is copied into TCNT1H.

The datasheet says clearly that the 16 bit registers of Timer 1 all use the same temp register, so there is (should be?) no need to read and write the same value from and to that register when copying data between the registers of the timer.

I'm not absolutely sure this works though, haven't tried it yet, I only use C, sometimes trying to look into Python. Asm is not my hobby.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

Quote:

all use the same temp register,

Internally! It's for double-buffering. It's not user accessible.

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

Quote:
Internally! It's for double-buffering. It's not user accessible.

Exactly.
The user copies the low byte of a 16 bit register of the timer to another 16 bit register and the AVR hardware automagically copies the high byte to and from the temp register to it's destination.

I did a little test with my newly written code and made a listing below. Each line is from my "terminal emulator" over the network send to the avr to read an register and the content of that register is echoed back. I added the comment later.

Register, content	; Comment.

 r.x4d.x000	; Startup, TCNT1H (temp) not used yet.
 r.x4d.x000	; Value does not change.
 r.x4c=.x6e	; TCNT1L
 r.x4c=.x0e	; Value changes because the timer is running.
 r.x4d=.x4f	; TCNT1H (temp) changed when reading TCNT1L
 r.x4d=.x4f	; TCNT1H (temp) Not change (timer is running)
 r.x46=.xff	; ICR1L  (temp) updated
 r.x47=.xd7	; ICR1H  This is the new value of temp.
 r.x47=.xd7	; Also does not change.
 r.x4d=.xd7	; TCNT1H  (temp) is same as ICR1H
 r.x4d=.xd7	; (8 minutes later) TCNT1H still the same.
 r.x4c=.xfe	; TCNT1L Timer1 is still running.
 r.x4c=.xde	; ,,	,,
 r.x4c=.x66	; ,,	,,
 r.x47=.x5d	; ICR1H. Temp when TCNT1L was read.
 r.x47=.x5d	; ICRH, no change, tmp register not updated.
 r.x4d=.x5d	; TCNT1H == ICR1H same temp register.
 r.x4d=.x5d	; idem.

This is not an exhaustive test but it seems to confirm my understanding of the datasheet and that my code for reading registers really works. Read access to TCNT1L or ICR1 updates the contents of the temp register and as long no other code changes the temp register that value can be used to write it directly into another high byte of a register which uses the same temp register.

Read access to OCR1A does not seem to update the temp register, but write access to OCR1AL should put the content of the temp register into OCR1AH. Even if the content of the temp register was directly from TCNT1L and not from one of the 32 internal register.

I haven't written code to write to register so I can't check this yet.

How usefull would an optimisation like this be?
It seems like a lot of work for saving 2 opcodes and a few cpu cycles. I mainly did it for fun, better understanding on how the temp register works and testing the code to read the contents of registers.


Could there be more interest in debugging code like this for al the folks who do not have avr studio and luxourious hardware? Maybe it't better for me to figure out how to run software for the dragon on my linux box.

Paul.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

Quote:
GetUint32() returns an uint32_t
Then how do you expect to put a uint32_t into a uint8_t and expect no loss of data? And why on Earth would you then treat that 8 bit value as a pointer?

Regards,
Steve A.

The Board helps those that help themselves.

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

@ Steve,

Quote:
uint32_t into a uint8_t and expect no loss of data
It's easy, just take control of the input into an existing function which is also able to handle bigger numbers for other purposes.

Quote:
And why on Earth would you then treat that 8 bit value as a pointer?

It's for "debugging", and it works as expected. I thought the reason I did this and the way it works should be easy to understand from the information in my first post. If you know a better way to adress the internal AVR registers, please share.

It all started when I wanted to know the contents of an interrupt enable register because a TOV1 was never executed while I was sure the right interrupts were enabled, etc. and I was tired of re-flashing the whole chip to look at the contents of a single register. So I wrote about 10 lines of code as an add-on to my program

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

Quote:
It's easy, just take control of the input into an existing function which is also able to handle bigger numbers for other purposes.
If it was so "easy", then why did you do it in a way that had absolutely no way of working?

Regards,
Steve A.

The Board helps those that help themselves.

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

@Steve,
What was supposed to not work? My original post was not about anything not working, it was only about a compiler warning I didn't understand.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

But that code did not work, except maybe by chance in some circumstances. 8 bits can simply not hold a 16 bit address.

Regards,
Steve A.

The Board helps those that help themselves.

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

Thanks Steve,

You finally made me realize what I oversaw.
The addresses I was using were not the register addresses, but the addresses where they are mapped in ram, and those are of course 16 bit.
The luxury of C put me to sleep the last 15 year and I never had to think about these addresses before.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

But pointers in C are always at least 16 bits no matter what they point to.

Regards,
Steve A.

The Board helps those that help themselves.