C Pointer and array - Page 1
Forum section: electronics / beginners

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 06:27:52 pm
content: hi,am trying to extract multiples 4 bytes from a 512Byte array so as example i wrote thisCode:unsigned char FILE_SWAP[]={0,0,0,0,1,1,1,1,2,2,2,2};unsigned long int *add0=&FILE_SWAP;unsigned long int *add1=&FILE_SWAP;unsigned long int *add2=&FILE_SWAP;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

author: ataradov
author_rank: Super Contributor
timestamp: October 08, 2015, 06:32:20 pm
content: Did not like as in error or warning?TryCode:unsigned long int *add0 = (unsigned long int *)&FILE_SWAP;

author: helius
author_rank: Super Contributor
timestamp: October 08, 2015, 06:34:53 pm
content: 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 writingCode:unsigned long int *add0=(void *) &FILE_SWAP;

author: Howardlong
author_rank: Super Contributor
timestamp: October 08, 2015, 06:37:25 pm
content: 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.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 06:47:35 pm
content: As errorError: a value of type "unsigned char *" cannot be used to initialize an entity of type "unsigned long *"Quote from: helius on October 08, 2015, 06:34:53 pmQuote from: ataradov on October 08, 2015, 06:32:20 pmAwesome both workThanks

author: grumpydoc
author_rank: Super Contributor
timestamp: October 08, 2015, 06:50:56 pm
content: QuoteWhy 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?

author: John Coloccia
author_rank: Super Contributor
timestamp: October 08, 2015, 06:55:52 pm
content: 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.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 07:00:45 pm
content: Quote from: Howardlong on October 08, 2015, 06:37:25 pmi 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.

author: miguelvp
author_rank: Super Contributor
timestamp: October 08, 2015, 07:00:54 pm
content: 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.

author: John Coloccia
author_rank: Super Contributor
timestamp: October 08, 2015, 07:08:49 pm
content: 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).

author: f1rmb
author_rank: Regular Contributor
timestamp: October 08, 2015, 07:11:21 pm
content: 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;unsigned long int *add1=&FILE_SWAP;unsigned long int *add2=&FILE_SWAP;should beunsigned char FILE_SWAP[]={0,0,0,0,1,1,1,1,2,2,2,2};unsigned long int *add0=&FILE_SWAP;unsigned long int *add1=&FILE_SWAP;unsigned long int *add2=&FILE_SWAP;Cheers.

author: grumpydoc
author_rank: Super Contributor
timestamp: October 08, 2015, 07:19:03 pm
content: Quote from: f1rmb on October 08, 2015, 07:11:21 pmNo, 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

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 07:19:23 pm
content: Quote from: grumpydoc on October 08, 2015, 06:50:56 pmthe 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.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 07:20:23 pm
content: Quote from: f1rmb on October 08, 2015, 07:11:21 pmyes it is, but this is a demo code to explain what i needed to do

author: grumpydoc
author_rank: Super Contributor
timestamp: October 08, 2015, 07:24:29 pm
content: Quote from: hamdi.tn on October 08, 2015, 07:19:23 pmOK, 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?

author: miguelvp
author_rank: Super Contributor
timestamp: October 08, 2015, 07:24:42 pm
content: Then you just need to cast the pointer to the base address and then loop through the 128 long ints with add0 where n goes from 0 to 127.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 07:26:03 pm
content: Quote from: grumpydoc on October 08, 2015, 07:19:03 pmnop , not at arbitrary addresses, every 4 bytes are independent.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 07:31:08 pm
content: Quote from: grumpydoc on October 08, 2015, 07:24:29 pmJust 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.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 08, 2015, 07:47:30 pm
content: Quote from: John Coloccia on October 08, 2015, 07:08:49 pmcould you please explain that ?

author: grumpydoc
author_rank: Super Contributor
timestamp: October 08, 2015, 07:47:58 pm
content: Quote from: hamdi.tn on October 08, 2015, 07:31:08 pmAssuming 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.

author: John Coloccia
author_rank: Super Contributor
timestamp: October 08, 2015, 10:57:27 pm
content: Quote from: hamdi.tn on October 08, 2015, 07:47:30 pmWhen 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:048128204816etc etc...multiples of 4.Addresses that are not aligned on word boundaries are:271322etc 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.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: October 09, 2015, 07:43:52 am
content: Make perfect sense, i totally ignored this detail thanks, well was really informative thanks everyone