EEVblog Electronics Community Forum

Electronics => Beginners => Topic started by: hamdi.tn on October 08, 2015, 06:27:52 pm

Title: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 06:27:52 pm
hi,
am trying to extract multiples 4 bytes from a 512Byte array so as example i wrote this

Code: [Select]
unsigned char FILE_SWAP[]={0,0,0,0,1,1,1,1,2,2,2,2};
unsigned long int *add0=&FILE_SWAP[0];
unsigned long int *add1=&FILE_SWAP[4];
unsigned long int *add2=&FILE_SWAP[8];

The idea is to be able able to read and write 4 bytes at once to a particular position in the array.
i tried this with IAR didn't like pointer with type different than the array it self. And i tried it with "MikroC" compiler and it worked.

What am doing wrong , or please suggest any correct way to do this.
Thanks

Title: Re: C Pointer and array
Post by: ataradov on October 08, 2015, 06:32:20 pm
Did not like as in error or warning?

Try
Code: [Select]
unsigned long int *add0 = (unsigned long int *)&FILE_SWAP[0];
Title: Re: C Pointer and array
Post by: helius on October 08, 2015, 06:34:53 pm
There may be alignment restrictions that the compiler is checking. AFAIK, the C standard allows compilers to check for that.
You could bypass the checks by writing
Code: [Select]
unsigned long int *add0=(void *) &FILE_SWAP[0];
Title: Re: C Pointer and array
Post by: Howardlong on October 08, 2015, 06:37:25 pm
You could use union(s) for this.

One caveat though is that it will be machine specific due to endianness and implementation: using a union to allow different typed access is frowned upon by C pedants but is commonplace in the real world. Also rather than using char and long you might want to use int8_t and int32_t from stdint.h as they are guaranteed to be the size you want across platforms.

Do you need to read a long across 32 bit boundaries? If so that may be verboten in some architectures giving a bus error.
Title: Re: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 06:47:35 pm
As error
Error[Pe144]: a value of type "unsigned char *" cannot be used to initialize an entity of type "unsigned long *"

There may be alignment restrictions that the compiler is checking. AFAIK, the C standard allows compilers to check for that.
You could bypass the checks by writing
Code: [Select]
unsigned long int *add0=(void *) &FILE_SWAP[0];
Did not like as in error or warning?

Try
Code: [Select]
unsigned long int *add0 = (unsigned long int *)&FILE_SWAP[0];



Awesome both work  ;D
Thanks  :-+
Title: Re: C Pointer and array
Post by: grumpydoc on October 08, 2015, 06:50:56 pm
Quote
The idea is to be able able to read and write 4 bytes at once to a particular position in the array.

Why do you want to read and write 4 bytes at a time?

What data is going in the array and what does it represent. From where, and how, do you obtain it?
Title: Re: C Pointer and array
Post by: John Coloccia on October 08, 2015, 06:55:52 pm
What you're doing is kind of dangerous and very non-portable. If you tell us what you're doing, we can probably suggest a much cleaner implementation.
Title: Re: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 07:00:45 pm
You could use union(s) for this.

One caveat though is that it will be machine specific due to endianness and implementation: using a union to allow different typed access is frowned upon by C pedants but is commonplace in the real world. Also rather than using char and long you might want to use int8_t and int32_t from stdint.h as they are guaranteed to be the size you want across platforms.

Do you need to read a long across 32 bit boundaries? If so that may be verboten in some architectures giving a bus error.

i usually use int8_t and int32_t , but those are not recognised by MikroC so to be compatible with both IDE i used char and long to test.
Title: Re: C Pointer and array
Post by: miguelvp on October 08, 2015, 07:00:54 pm
Just to be a bit more specific as in why this is dangerous and non-portable is that the processor endianness will change how the bytes are organized in memory.
Also it can cause the processor to produce exceptions for unaligned access.
Title: Re: C Pointer and array
Post by: John Coloccia on October 08, 2015, 07:08:49 pm
Exactly...you definitely need to worry about alignment issues here, even more than endianess. A traditional hack would be to union it with something like a long int* to guarantee alignment, but there's probably a better way to handle this than arrays. Typically, you would malloc the memory (which has guaranteed alignment for all types).
Title: Re: C Pointer and array
Post by: f1rmb on October 08, 2015, 07:11:21 pm
I agree with others about dangerousness and non-portability. Anyway, your code looks wrong with offsets:

unsigned char FILE_SWAP[]={0,0,0,0,1,1,1,1,2,2,2,2};
unsigned long int *add0=&FILE_SWAP[0];
unsigned long int *add1=&FILE_SWAP[1];
unsigned long int *add2=&FILE_SWAP[2];

should be

unsigned char FILE_SWAP[]={0,0,0,0,1,1,1,1,2,2,2,2};
unsigned long int *add0=&FILE_SWAP[0];
unsigned long int *add1=&FILE_SWAP[4];
unsigned long int *add2=&FILE_SWAP[8];

Cheers.
Title: Re: C Pointer and array
Post by: grumpydoc on October 08, 2015, 07:19:03 pm
I agree with others about dangerousness and non-portability. Anyway, your code looks wrong with offsets:
No, I think the OP actually wanted to be able to access 4 bytes at arbitrary addresses, not 32-bit aligned addresses.

However I suspect this is an X-Y problem; we need to know what the OP is really trying to accomplish.


"I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships."

        — Linus Torvalds
Title: Re: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 07:19:23 pm
Quote
The idea is to be able able to read and write 4 bytes at once to a particular position in the array.

Why do you want to read and write 4 bytes at a time?

What data is going in the array and what does it represent. From where, and how, do you obtain it?

the 512 Bytes are loaded from an EEPROM to RAM and contain  some parameters ( 4 bytes unsigned integer type ) that can be accessed by different process either by writing or reading them.
Those setting are a bit dangerous and need to be sure that their value are correct all the time and not changed by any EM event. So a mechanism verify those values (with a checksum).
Those setting are independent and in a previous program i wrote they were separated in different table depending on their functionality and i find it a bit annoying to check them table by table. sor simplicity i thought to download the whole EEPROM Sector to the RAM and execute the checksum from there, with a simple loop to cover the whole array. And address every setting with a 4 byte size pointer.



Title: Re: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 07:20:23 pm
I agree with others about dangerousness and non-portability. Anyway, your code looks wrong with offsets:

unsigned char FILE_SWAP[]={0,0,0,0,1,1,1,1,2,2,2,2};
unsigned long int *add0=&FILE_SWAP[0];
unsigned long int *add1=&FILE_SWAP[1];
unsigned long int *add2=&FILE_SWAP[2];

should be

unsigned char FILE_SWAP[]={0,0,0,0,1,1,1,1,2,2,2,2};
unsigned long int *add0=&FILE_SWAP[0];
unsigned long int *add1=&FILE_SWAP[4];
unsigned long int *add2=&FILE_SWAP[8];

Cheers.

yes it is, but this is a demo code to explain what i needed to do
Title: Re: C Pointer and array
Post by: grumpydoc on October 08, 2015, 07:24:29 pm
the 512 Bytes are loaded from an EEPROM to RAM and contain  some parameters ( 4 bytes unsigned integer type ) that can be accessed by different process either by writing or reading them.
Those setting are a bit dangerous and need to be sure that their value are correct all the time and not changed by any EM event. So a mechanism verify those values (with a checksum).
Those setting are independent and in a previous program i wrote they were separated in different table depending on their functionality and i find it a bit annoying to check them table by table. sor simplicity i thought to download the whole EEPROM Sector to the RAM and execute the checksum from there, with a simple loop to cover the whole array. And address every setting with a 4 byte size pointer.
OK, I see.

OK. Do you want to just checksum them in RAM or use them as well? Is the 512 bytes all data/parameters or is there some code in there as well?
Title: Re: C Pointer and array
Post by: miguelvp on October 08, 2015, 07:24:42 pm
Then you just need to cast the pointer to the base address and then loop through the 128 long ints with add0[n] where n goes from 0 to 127.
Title: Re: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 07:26:03 pm
I agree with others about dangerousness and non-portability. Anyway, your code looks wrong with offsets:
No, I think the OP actually wanted to be able to access 4 bytes at arbitrary addresses, not 32-bit aligned addresses.

However I suspect this is an X-Y problem; we need to know what the OP is really trying to accomplish.


"I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships."

        — Linus Torvalds

nop , not at arbitrary addresses, every 4 bytes are independent.
Title: Re: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 07:31:08 pm
the 512 Bytes are loaded from an EEPROM to RAM and contain  some parameters ( 4 bytes unsigned integer type ) that can be accessed by different process either by writing or reading them.
Those setting are a bit dangerous and need to be sure that their value are correct all the time and not changed by any EM event. So a mechanism verify those values (with a checksum).
Those setting are independent and in a previous program i wrote they were separated in different table depending on their functionality and i find it a bit annoying to check them table by table. sor simplicity i thought to download the whole EEPROM Sector to the RAM and execute the checksum from there, with a simple loop to cover the whole array. And address every setting with a 4 byte size pointer.
OK, I see.

OK. Do you want to just checksum them in RAM or use them as well? Is the 512 bytes all data/parameters or is there some code in there as well?

Just data, and once those data are stored in RAM when booting, will be checked only in RAM , if anything go wrong. the program download it again from the EEPROM.
Yap they will be used and checked , but when used the process writing them will recalculate CS again.
Title: Re: C Pointer and array
Post by: hamdi.tn on October 08, 2015, 07:47:30 pm
Exactly...you definitely need to worry about alignment issues here, even more than endianess. A traditional hack would be to union it with something like a long int* to guarantee alignment, but there's probably a better way to handle this than arrays. Typically, you would malloc the memory (which has guaranteed alignment for all types).

could you please explain that ?
Title: Re: C Pointer and array
Post by: grumpydoc on October 08, 2015, 07:47:58 pm
Just data, and once those data are stored in RAM when booting, will be checked only in RAM , if anything go wrong. the program download it again from the EEPROM.
Yap they will be used and checked , but when used the process writing them will recalculate CS again.
Assuming they are all 4-byte words then miguelvp is correct - declare them, correctly, as an array of uint32_t and calculate the checksum as he described.
Title: Re: C Pointer and array
Post by: John Coloccia on October 08, 2015, 10:57:27 pm
Exactly...you definitely need to worry about alignment issues here, even more than endianess. A traditional hack would be to union it with something like a long int* to guarantee alignment, but there's probably a better way to handle this than arrays. Typically, you would malloc the memory (which has guaranteed alignment for all types).

could you please explain that ?

When you just say:

char a[];

you are not guaranteed the the address of a (i.e. the first byte of the array) is aligned on any memory boundary. For example, lets say you particular processor has a 32 bit word size (4 bytes). Addresses that are aligned on a word boundary are things like:

0
4
8
128
2048
16
etc etc...multiples of 4.

Addresses that are not aligned on word boundaries are:
2
7
13
22

etc etc...NOT multiples of 4.

Now what happens when you take an array of characters that happens to start on address 7, for example, and cast it to an int? I don't know either. It depends on your processor. Some processors will deal with it and simply take a performance hit. Other processors assume that 32 bit operations are aligned on 32 bit boundaries, and they can do silly things like simply ignoring the first two bits of the address.

See, what goes on behind the scenes is that often times processors are optimized to work very efficiently on certain size quantities, like a 32 bit word, and even if all you want is a character, you may just get all 32 bits anyway that then get thrown away unused. On the flip side, if it knows it's operating on a word (because your compiler made the call to do 32 bit math instead of 8 bit math), it can make a lot of simplifying assumptions to get much better performance. This comes at the cost of flexibility. In other words, you'd better not call 32 bit functions on misaligned data because the results you get will be highly dependent on really esoteric details of your compiler, linker and processor.

I hope that makes sense. Stuff like this doesn't come up too often just in normal programming, but it comes up a lot anytime you need to interface with the outside world (files, sensors, other embedded thingamabobs) because data often come in as characters or some other inconvenient size.

memcpy() is theoretically always safe if I recall correctly, but in practice compilers will often replace this with a call to an optimized version...which assumes things like word aligned data. You really need to be careful when using datatype smaller than the word size and then casting away type. Once you cast it away to something else (typically int* or void*), you're totally on your own and you have to worry about this stuff.

edit:
So this is why I suggested malloc() or a union with an int. Malloc() guarantees proper alignment for ALL types...sometimes it just allocates on page boundaries (explains why you can sometimes run out of memory with malloc() when you actually have TONS of memory left, you think). If you do a union, you are guaranteed proper alignment for the biggest type in the union.
Title: Re: C Pointer and array
Post by: hamdi.tn on October 09, 2015, 07:43:52 am
Make perfect sense, i totally ignored this detail thanks, well was really informative thanks everyone  :D