View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Help with pointers |
Posted: Sat Aug 22, 2015 7:54 am |
|
|
I cannot understand the following line of code from the internal_eeprom.c file in the CCS drivers. Is there a simpler way to write this, more than one line is OK for me if it makes it easier to understand.
Code: | *((int8 *)(&data) + i) = read_eeprom(address + i);
|
The first * is a pointer to everything in the brackets and &data is where the address of the pointer to data is stored? I don't understand int8* (the pointer is an integer?)
I think the full code (shown last in this post) can be simplified (corrected?) to the following for pcm and PIC16F1938.
Code: | float read_float_eeprom(int EEPROM_address)
{
float data;
int i;
for(i = 0; i < 4; i++)
*((int8 *)(&data) + i) = read_eeprom(EEPROM_address + i);
return(data);
}
| The full function is below. I assume INT_EEPROM_ADDRESS is supposed to be the type for address but I don't understand this either.
Code: | // Purpose: Read a 32 bit floating point number from internal eeprom
// Inputs: An eeprom address
// Outputs: The floating point number read from the internal eeprom
float32 read_float_eeprom(INT_EEPROM_ADDRESS address)
{
float32 data;
#ifdef __PCD__
read_eeprom(address, &data, 4);
return(data);
#else
int8 i;
for(i = 0; i < 4; i++)
*((int8 *)(&data) + i) = read_eeprom(address + i);
return(data);
#endif
} |
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Sat Aug 22, 2015 8:03 am |
|
|
OK I found the answer to the INT_EEPROM_ADDRESS at the beginning of the code:
Code: | // Used to adjust the address range
#ifndef INT_EEPROM_ADDRESS
#if getenv("DATA_EEPROM") > 255
#define INT_EEPROM_ADDRESS unsigned int16
#else
#define INT_EEPROM_ADDRESS unsigned int8
#endif
#endif |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Aug 22, 2015 10:48 am |
|
|
Quote: | I don't understand int8* |
We have to sequentially move four bytes from eeprom into a float
variable. (A float variable consists of four bytes, internally).
To do this, we have to temporarily change the float pointer into a byte
pointer. Then we can step through a for() loop 4 times, and fill up the
float variable with the necessary 4 bytes. Each time we go through
the for() loop, we add an offset (0 to 3) so that each byte in the float
variable will be written to sequentially.
The 'int8 *' tells the compiler to treat the float address temporarily
as a byte pointer. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Sat Aug 22, 2015 11:51 am |
|
|
So data is a floating point variable stored at some location determined by the compiler. It takes 4 bytes.
We arrive with a starting EEPROM_address.
For the first pass:
The EEPROM is read at "EEPROM_address + 0" and stored at location "data address + 0"
For the second pass:
The EEPROM is read at "EEPROM_address + 1" and stored at location "data address + 1"
and so on to fill 4 bytes.
Then data is returned as a floating point number.
I think I understand it now. Thanks PCM programmer.
(ps. this is to store AmpHours in my AmpHour meter which is now working. I will add the working code when ready) |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Aug 24, 2015 7:46 am |
|
|
Why does the compiler not think that (int8 *)(&data) are to be multiplied and give an error?
How is the *((int8 *)(&data) + i) handled by the compiler?
I am trying to understand the use of the brackets so I can write my own versions. Should I be looking in a general book on C or is this a CCS compiler issue? I like to understand code, not just copy it.
I understand what it does, but not how it is handled. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Aug 24, 2015 8:07 am |
|
|
General book on C.
int8 * is a type, not a variable. Casting (type) in brackets in front of a variable, is a standard C construct.
Multiplication always has two values. *, on it's own in front of a variable means 'the value pointed to by'.
Similarly &, as a logical operator always has two values. &variable, gives the 'address of' the variable.
Generally in C, if you increment a pointer the pointer increments to the next variable of the type it is declared to point 'to'. So if you have a pointer to a float, and increment it, it moves forward by four bytes, to the next float. This is why the pointer has to be cast to say 'treat as a pointer to an int8', so it is incremented to the next byte, not to the next float.
It is standard C. The only thing 'different', is the size of variables. So on most common C's, 'int' is a signed int16. However K&R (the original bible for C - written by the language author's), specifically refers to the types always being processor specific, and even gives the example of 12bit integers on the early PDP computers. CCS has stuck to this to keep things efficient. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Aug 24, 2015 10:34 am |
|
|
Thanks Ttelmah.
I was looking in the wrong place (Embedded C programming by Mark Siegesmund, excellent) for the answer. I needed the right buzzword to find the answer. I have never heard of "Cast" but looking it up in K&R I now understand. I have never had a course in C which obviously shows. |
|
|
|