Author Topic: 2 byte value into 2 separate 1 byte values  (Read 4565 times)

0 Members and 1 Guest are viewing this topic.

Offline etnel

  • Contributor
  • Posts: 10
  • Country: se
2 byte value into 2 separate 1 byte values
« on: July 15, 2021, 06:50:03 pm »
Hello, I'm currently trying to store 2 values of 2 bytes each to the EEPROM to my PIC16f1827. The EEPROM stores single bytes. How would I divide my value into 2 bytes to write them? And how do I then read them into one single value again?
 

Online Kleinstein

  • Super Contributor
  • ***
  • Posts: 9817
  • Country: de
Re: 2 byte value into 2 separate 1 byte values
« Reply #1 on: July 15, 2021, 07:39:43 pm »
In C there is the union structure. This way the same memory space can be accessed in different ways, e.g. as an integer or as 2 bytes.
Which of the byte is the high and low byte depends on the CPU used, but for storage this should no be an issue.

An alterntive would be to use a pointer and do a cast ont he pointer type.

A protable way is to use bit masks and shifts for a conversion.
 

Offline golden_labels

  • Frequent Contributor
  • **
  • Posts: 406
  • Country: pl
Re: 2 byte value into 2 separate 1 byte values
« Reply #2 on: July 16, 2021, 01:42:03 am »
(Language not specified; assuming C from the context)

The second option offered by Kleinstein is fine. Casting to a char* is portable and well-defined in this particular scenario: the data is not expected to be exchanged with other code, so endianess, ranges, alignment and trap representations are not an issue. The exception to this is using a different compiler or options and wishing to maintain the same EEPROM data. If that’s the case, you may consider the third option. But I would not waste time on doing so until such a neccessity arises. Not laziness; quite opposite: code quality. This is the simplest method, with no potential for introducing subtle bugs, and easiest for compilers to implement efficiently.

Unions in this case give no advantages: that would only cause more noise in the code. The behaviour is identical.
Worth watching: Calling Bullshit — protect your friends and yourself from bullshit!
 

Offline TheCalligrapher

  • Contributor
  • Posts: 37
  • Country: us
Re: 2 byte value into 2 separate 1 byte values
« Reply #3 on: July 16, 2021, 03:06:50 am »
Hello, I'm currently trying to store 2 values of 2 bytes each to the EEPROM to my PIC16f1827. The EEPROM stores single bytes. How would I divide my value into 2 bytes to write them? And how do I then read them into one single value again?

Very simple. If `V` is your two-byte value, then lower [8-bit] byte is obtained as `V % 256` and upper byte is obtained as `V / 256`. If you so prefer, you can replace division by shifting and masking. Makes no difference. One might also add that it is preferrable to perform operations like that in the domain of an unsigned integer type.

This is always more efficient (or as efficient as) that any alternative approaches based on type punning through unions, casting to `unsigned char *` or somesuch.  Never use type punning unless you absolutely have to.
« Last Edit: July 16, 2021, 03:11:19 am by TheCalligrapher »
 

Offline AntiProtonBoy

  • Frequent Contributor
  • **
  • Posts: 939
  • Country: au
  • I think I passed the Voight-Kampff test.
Re: 2 byte value into 2 separate 1 byte values
« Reply #4 on: July 16, 2021, 05:33:50 am »
memcpy is your friend here.
 

Offline BBBbbb

  • Supporter
  • ****
  • Posts: 257
  • Country: cs
Re: 2 byte value into 2 separate 1 byte values
« Reply #5 on: July 16, 2021, 07:28:17 am »
just cast as suggested in first 2 comments
Avoid complicated solutions and ones depending on additional libraries.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3400
  • Country: fr
Re: 2 byte value into 2 separate 1 byte values
« Reply #6 on: July 16, 2021, 07:47:58 am »
I don't get some of those answers. Why to mess with pointers and structures? Uh and memcpy? Seriously?

Assuming this is C and your data are really 16 bit, this is all you need to do:

Code: [Select]
uint16_t original_data;

uint8_t b1,b2;

b1 = (uint8_t) (original_data & 0xff);
b2 = (uint8_t) ((original_data >> 8) & 0xff);

Using a struct/union is actually potentially buggy, because of alignment issues - the compiler can and will insert invisible "padding", depending on the constraints of the target platform. So that is non-portable and may bug on some platforms and work on others. It will be probably OK in the OP's case but then they may try to serialize the data and will wonder why on some platform the struct has 4 bytes size and on another just 3 ... (no idea about that OP's PIC - PIC compilers can do weird stuff).

Using modulo/division actually does not behave the same as shifting/masking - it implicitly depends on the byte order of the platform/data! With shifting and masking you are making that choice explicit. Again, may work in this case but it is a poor habit to get into, doesn't scale to wider data types and it is a good source of endian-related bugs.

Also, don't use types like "char" or "int" when you need exact sizes. Those are poorly defined, the standard only says that char is at least 8 bits and that int needs to be wider than char but not how many bits they really have.
« Last Edit: July 16, 2021, 07:52:26 am by janoc »
 
The following users thanked this post: Bassman59, rs20, newbrain

Offline BBBbbb

  • Supporter
  • ****
  • Posts: 257
  • Country: cs
Re: 2 byte value into 2 separate 1 byte values
« Reply #7 on: July 16, 2021, 07:59:37 am »
I don't get some of those answers. Why to mess with pointers and structures? Uh and memcpy? Seriously?
I (very strongly) agree about memcpy comment, but pointer to array has it's advantage.
Usually there are available functions for multiple byte writes, where you just pass the address of the first one.
just doing something like:
e2pW( (char*)&dataIn16bits , address, #ofBytes2wirte)
is simple, quick and easy.

Of course, some checks about byte order are on the user to be done.

Not saying your proposition is bad, it's clean and simple to understand, real textbook (even with the precautionary masking), but the cast one is quick and efficient, very useful when working on targets with little resources.

 

Offline TheCalligrapher

  • Contributor
  • Posts: 37
  • Country: us
Re: 2 byte value into 2 separate 1 byte values
« Reply #8 on: July 16, 2021, 08:52:45 am »
is simple, quick and easy.

... and incorrect. Type-punning solutions are vastly inferior to arithmetic solutions in more ways than one. But if you are dead set on using memory reinterpretation, at least remember not to use `char`. It is either `unsigned char` or `uint8_t`.
 

Offline BBBbbb

  • Supporter
  • ****
  • Posts: 257
  • Country: cs
Re: 2 byte value into 2 separate 1 byte values
« Reply #9 on: July 16, 2021, 01:45:09 pm »
is simple, quick and easy.

... and incorrect. Type-punning solutions are vastly inferior to arithmetic solutions in more ways than one. But if you are dead set on using memory reinterpretation, at least remember not to use `char`. It is either `unsigned char` or `uint8_t`.
could you elaborate on the vast inferiority (apart from "safer" and more readable) and focus the exact use case.
I'm really interested if you have another angel, mostly efficiency related.

also what would be the difference in the above example between signed and unsigned char (save to eeprom)?
Anyways should cast to whatever is the receiving parameter is in the provided e2p write function.
regarding types we can play the target/compiler/C standard game all day, and I could say he might not have uint8_t available... there is not much data shared by the OP to discuss it, yes uintX_t is absolutely superior, but have your own typedef header file checked and adjusted for each project is probably the only universal way for portability
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3400
  • Country: fr
Re: 2 byte value into 2 separate 1 byte values
« Reply #10 on: July 16, 2021, 01:55:00 pm »
...yes uintX_t is absolutely superior, but have your own typedef header file checked and adjusted for each project is probably the only universal way for portability

Uuuuh, no! That's actually a pretty good way to shoot yourself in the foot when an algorithm assumes one size and you have helpfully typedeffed it to something else in some obscure header.

stdint.h is available pretty much everywhere with a reasonably recent C compiler (reasonably recent - released in the last 15 years or so). It is part of the now old C99 standard, not even the more recent C11 one.

 

Offline BBBbbb

  • Supporter
  • ****
  • Posts: 257
  • Country: cs
Re: 2 byte value into 2 separate 1 byte values
« Reply #11 on: July 16, 2021, 03:03:57 pm »
...yes uintX_t is absolutely superior, but have your own typedef header file checked and adjusted for each project is probably the only universal way for portability

Uuuuh, no! That's actually a pretty good way to shoot yourself in the foot when an algorithm assumes one size and you have helpfully typedeffed it to something else in some obscure header.

stdint.h is available pretty much everywhere with a reasonably recent C compiler (reasonably recent - released in the last 15 years or so). It is part of the now old C99 standard, not even the more recent C11 one.
I can tell you from personal experience that that is not an option in many automotive projects.
And in many more applications std is unwelcomed.

yes typedeffing requires caution, and that should be on your checklist when porting to a new target, but it gives you an universal solution in a single file, even for legacy projects (yes there are projects still obeying C89/90)

OP should be using in his personal projects unitX_t, but since we're all here nitpicking on nuances of C ...

I stay by my original statement - for his use case casting is a simple and effective solution. Based on the "difficulty" of his question it does not look like it's a serious commercial project with future of porting. More like learning project. And to understand what's going on behind this casting, would teach him some tricks about C and memory (as would this argument here).
His biggest problem might be running out of resources (which I noticed in some hobby projects to be an issue) due to many unoptimized code reuse from online examples, or unnecessary importing of libraries and here casting helps a little bit.

 

Offline TheCalligrapher

  • Contributor
  • Posts: 37
  • Country: us
Re: 2 byte value into 2 separate 1 byte values
« Reply #12 on: July 16, 2021, 04:35:56 pm »
could you elaborate on the vast inferiority (apart from "safer" and more readable) and focus the exact use case.

I'm just referring to the general principle: involving memory into an operation that doesn't have to involve memory is always a pessimization. In other abstract terms, it seems that many participants here somehow assumed that the original operation is applied to an lvalue, while in reality there's absolutely nothing lvalue-specific neither in the general problem not in the original question.

(I won't even mention byte-ordering dependency. Within the context of the orignal question it is not clear whether it is a problem at all.)

One can try to defend type-punning solutions by claiming that their compiler always generates the most optimal code for such solutions, but in reality this is just compiler's being smart enough to see through the intent and undoing the pessimization.
 
The following users thanked this post: newbrain

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3400
  • Country: fr
Re: 2 byte value into 2 separate 1 byte values
« Reply #13 on: July 16, 2021, 06:34:30 pm »
I can tell you from personal experience that that is not an option in many automotive projects.

You mean that automotive projects are still being built (as opposed to old machines maintained) with C compilers from before the year 2000? I think in that case there are bigger problems to worry about than the lack of stdint.h ...

And in many more applications std is unwelcomed.

Not sure what you mean by "std". stdint.h is literally a header full of typedefs for your compiler & platform, nothing else. It is part of the C language spec, not even the standard library, unlike e.g. malloc or the string handling functions.


His biggest problem might be running out of resources (which I noticed in some hobby projects to be an issue) due to many unoptimized code reuse from online examples, or unnecessary importing of libraries and here casting helps a little bit.

If you are squeezing the code so much that saving few bytes of flash (because that's all what you could save by pointer casting instead of shifting/masking, if that) makes the difference, then really there are bigger issues there.
 

Offline BBBbbb

  • Supporter
  • ****
  • Posts: 257
  • Country: cs
Re: 2 byte value into 2 separate 1 byte values
« Reply #14 on: July 16, 2021, 08:11:00 pm »
...

Seems you have not worked on products that require longer support... nor safety critical ones...

Ok imagine you drive a car made in early 2010s. What do you think when the development for different ECUs started for that car? 5 years before could easily be the case, but it could be a reuse of the ECU from the previous generation (even older) with just added feature, where the manufacturer is looking to keep the development on a tight budget and does not want to migrate to newer tools, drivers, standards... (this costs a lot on safety critical projects)

Now imagine you need to comply with an industry standard like MISRA 2004 (remember it's 2005, so this is the latest and greatest one...), but oh MISRA 2004 does not support C99? how come? Well no commercial C99 embedded compiler is available at the time of its publication.

OK now fast forward to 2021 and your car from early 2010s. You'd be pretty pissed if you can't buy a spare part, now wouldn't you?
So the manufacturer is still making ECUs for your car, but somewhere along the line sourcing of some components became difficult, changes were made to the design, so some modifications of code had to be made to reflect those changes (e.g. a new OCX with longer settling time, that now needs to be accounted for in code)
So there is a programmer somewhere working on your new spare ECU, that is making some modifications on a C89 compliant code...

Medical might be even worse if it is an FDA approved product. Any single change is an enormous PITA in money, time and effort... That's actually why US is 2-3 generations behind Europe regarding some specialized medical devices that don't have consumables (the cash cow of the medical device industry). Manufacturers don't see the ROI on some of those devices.

Oh and byte counting, yup that's common too at low level embedded that ships in high volume. I was on one project counting free bytes manually in the intel hex file, because memory map tool was not doing a got job for the specific uC. (and no, a better one was not available, as it is often the case with uC not available to the public)
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 4394
  • Country: fi
Re: 2 byte value into 2 separate 1 byte values
« Reply #15 on: July 17, 2021, 07:45:31 am »
In a nutshell: "Always implement your own stdint.h because in some automotive environment unchanged from 1990's, stdint.h may not be available".

How terrible advice.

Definitely always use the standardized typedefs in stdint.h. If not available in some esoteric environment, indeed write your own. I strongly suggest then following the standard naming of stdint.h.

This is an interesting thread to read; such basic beginner questions make people pop up left and right showing off some very interesting bubbles they live in.

janoc's piece of code is the most sane and most easily understood; also most widely used.

Aliasing packed structs in unions have its uses, though, and should be considered when the manual maintenance of manual shift operations becomes too big and error prone of a task, but initially it needs some care and understanding.
« Last Edit: July 17, 2021, 07:48:22 am by Siwastaja »
 

Offline AndersJ

  • Frequent Contributor
  • **
  • Posts: 350
  • Country: se
Re: 2 byte value into 2 separate 1 byte values
« Reply #16 on: July 17, 2021, 08:27:07 am »
Code: [Select]
uint16_t original_data;

uint8_t b1,b2;

b1 = (uint8_t) (original_data & 0xff);
b2 = (uint8_t) ((original_data >> 8) & 0xff);

Is the mask with FF neccessary?
Isn’t the typecast to uint8_t all that is needed?
"It should work"
R.N.Naidoo
 

Offline BBBbbb

  • Supporter
  • ****
  • Posts: 257
  • Country: cs
Re: 2 byte value into 2 separate 1 byte values
« Reply #17 on: July 17, 2021, 03:00:09 pm »
In a nutshell: "Always implement your own stdint.h because in some automotive environment unchanged from 1990's, stdint.h may not be available".

How terrible advice.

And who advised that?
Please go back and read the thread with a bit more concentration.
It was a following sentence from me:
Quote
regarding types we can play the target/compiler/C standard game all day, and I could say he might not have uint8_t available... there is not much data shared by the OP to discuss it, yes uintX_t is absolutely superior, but have your own typedef header file checked and adjusted for each project is probably the only universal way for portability

I explicitly said that if you want to play the nitpicking game - saying always use stdint has it's issues as well in some cases, and I gave an example. And all this originated from the bashing of type casting in a very specific example, were it just gets the job done efficiently. I really don't like bashing features without looking into exact context. I asked for a bit more details on downfall in the exact example, not sure I got it (maybe I missed it), just standard "general" against arguments...
packed directive gets the same treatment, but it has it's application as you pointed out. Yes it's bad in more than 99% cases, but there is an application.

Another thing that I find a bit surprising is how some perceive standards and it's propagation to projects.
Look at C++20, not sure apart from VS any other compiler supports it fully. How long do you think it needed C99 to become industry standard? (not talking only about automotive)
You might have had wide support for x86 in 1 or 3 years, but what about compilers for application specific MCUs? Do you think those are a small part of the embedded industry? And then you have industry specific standards that come...
Also not all projects have a development cycle of up to a year, some are developed for 3-5 years, and then put into production for 10+years...
So saying oooh you're working in the 90s is very shortsighted.

If I had to guess, most used standard today in the embedded industry world is C99 (not counting things like mobile phones and other devices that have SoCs more powerful than my previous PC and most dev being done in Java or some other higher level language).

...such basic beginner questions make people pop up left and right showing off some very interesting bubbles they live in
That's the beauty of this forum
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 7331
  • Country: fr
Re: 2 byte value into 2 separate 1 byte values
« Reply #18 on: July 17, 2021, 05:40:11 pm »
In a nutshell: "Always implement your own stdint.h because in some automotive environment unchanged from 1990's, stdint.h may not be available".

How terrible advice.

Indeed. It's mind-boggingly wrong. :horse:

If you work with compilers that do not support C99 at least, well obviously you don't have access to stdint (or it may be that they do but your team's rules are to write in pure C90 for instance). In that case, your team probably has come up with ad-hoc solutions for years already, or sometimes decades. Of course you'll use them then - and you'll have no choice either. Unless you're the boss, in heavily regulated industries, you usually just shut up and do as you're told.

Now if you have access to compilers supporting C99 and can (or are mandated to) use C99 or later, not using stdint would be completely dumb.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 7331
  • Country: fr
Re: 2 byte value into 2 separate 1 byte values
« Reply #19 on: July 17, 2021, 05:54:50 pm »
As to the original question, if we have to assume that the OP meant to use C (which they did not specify), there are of course ways that are more or less portable.
The most portable way would just be to use MSB = N / 256 and LSB = N % 256 (and conversely use arithmetic for the inverse operation). That's guaranteed to work on any platform, whatever the endianness is and whatever the compiler is. Playing with memory access "usually" works, but is not portable. Using union is even worse: nothing guarantees that "overlaid" members in unions actually point to the same memory area exactly (in practice they may be aligned differently). The standard explicitely says that IIRC. It may work on a specific target with a specific compiler and specific options (yes, that's a lot of "specifics"), but is 100% non-portable. Avoid this.

Also note that memory access or union tricks may remotely look more efficient to you (so you may want to trade off portability), but it's not even. Any decent compiler will usually optimize any of the 3 possibilities above yielding pretty much the exact same object code. Likewise, using shifts and bitwise 'and' won't make a difference. Any decent compiler will translate "MSB = N / 256; LSB = N % 256;" and "MSB = N >> 8; LSB = N & 0xFF" in exactly the same way. Do not bother trying to micro-optimize this.
 

Offline etnel

  • Contributor
  • Posts: 10
  • Country: se
Re: 2 byte value into 2 separate 1 byte values
« Reply #20 on: July 17, 2021, 06:19:00 pm »
Wow, some of you made me think this was harder than it actually was.
Well, this is my shot at it, works flawlessly. I don't know about the speed etc, but it is fine for my current application.
Code: [Select]
uint16_t original;

uint8_t left,right;

//to read

//*reading 2 bytes from eeprom*
original = 0;

original = right | (left<<8);



//to write

right = original;
left = original >> 8;

//*writing 2 bytes to eeprom*

« Last Edit: July 17, 2021, 06:48:31 pm by etnel »
 

Online Cerebus

  • Super Contributor
  • ***
  • Posts: 8465
  • Country: gb
Re: 2 byte value into 2 separate 1 byte values
« Reply #21 on: July 17, 2021, 06:24:58 pm »
Code: [Select]
uint16_t original_data;

uint8_t b1,b2;

b1 = (uint8_t) (original_data & 0xff);
b2 = (uint8_t) ((original_data >> 8) & 0xff);

Is the mask with FF neccessary?
Isn’t the typecast to uint8_t all that is needed?

In terms of making the compiler happy and getting the semantics you want - probably not necessary.

In terms of clearly indicating your intentions to the next programmer to read the code - priceless.
Anybody got a syringe I can use to squeeze the magic smoke back into this?
 
The following users thanked this post: AndersJ

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 7331
  • Country: fr
Re: 2 byte value into 2 separate 1 byte values
« Reply #22 on: July 17, 2021, 06:57:37 pm »
Code: [Select]
uint16_t original_data;

uint8_t b1,b2;

b1 = (uint8_t) (original_data & 0xff);
b2 = (uint8_t) ((original_data >> 8) & 0xff);

Is the mask with FF neccessary?
Isn’t the typecast to uint8_t all that is needed?

In terms of making the compiler happy and getting the semantics you want - probably not necessary.

In terms of clearly indicating your intentions to the next programmer to read the code - priceless.

Yes. A couple things to note:
- The compiler (at least GCC) will be happy even if you omit the '(uint8_t)' cast and the '& 0xFF' mask. Even at '-Wall'. Yep. For it to emit a warning at all, you need 1/ to enable the '-Wconversion' option (which is not enabled by default with '-Wall') and 2/ not do neither the cast nor the masking. Even just the masking without the cast will silence warnings. Conversion issues are actually very important to catch IMHO, and are particularly easy to introduce in C - so I almost always enable the '-Wconversion' flag.
- Failing to understand integer promotion rules can lead to bugs as well. Wouldn't come into play in the above code, but for the inverse operation, it could: 'original = right | (left<<8);'. In this expression, left which is a uint8_t will be promoted to int before getting shifted left. In this case, it shouldn't be a problem as long as 'int' on the given platform is at least 16-bit. If it isn't, then you'll just get 0. ('int' type is at least 16-bit on most plaforms these days, even 8-bit targets, but this can cause issues for wider integers.) To mitigate this, you'd have to explicitely cast 'left' to the wider type before shifting it.
 

Offline golden_labels

  • Frequent Contributor
  • **
  • Posts: 406
  • Country: pl
Re: 2 byte value into 2 separate 1 byte values
« Reply #23 on: July 18, 2021, 12:04:53 am »
Many similar comments have appeared since my post and I am late to answer each separately, so this is an aggregate response.

Type punning in general is unportable and, unless unions are used, is actually undefined in C. I would completely agree with you and usually I strongly oppose such solutions, but this is not a general case. This is a constrained scenario in which the goal is to obtain byte-array representation of a value, a representation to never be used by a different piece of code. And C has that very operation defined. Word “bytes” is the key here; C treats char specially: it has no trap representations (if one would care about that), it has no alignent requirements, every object can have each and every char of it read and written, and every byte-copy of an object is always guaranteed to be fine. The operation is explicitly defined by C as being always valid. There is no way it can ever go wrong.

The alternative solution, based on arithmetic, may be be valid, but may as well contain a bug. Merely understanding what the arithmetic solution does in a single (platform, compile, settings) triple takes more time and effort than applying the byte-access version, which is always valid. On top of that most C programmers never learned C and may easily misinterpret such code.(1)

To sum it up, we have two solutions. One explicitly defined to always work properly, the other that may contains bugs. The first one is also “visually” doing what it is asked to do. Which one should be chosen in that situation? I opt for the first one.

As for performance, for modern compiler they are likely to generate code that is nearly as fast — possibly even identical code. In particular creating a temporary array and copying data to it using memmove is most likely to generate optimal code: a no-op introducing zero cost, reading directly from registers used to pass the serialized value.
____
(1) If you don’t believe, ask people here to explain: what data types are involved in etnel’s code and if line 6 of that code contains (or not) signed oveflow.
Worth watching: Calling Bullshit — protect your friends and yourself from bullshit!
 
The following users thanked this post: Siwastaja

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 4394
  • Country: fi
Re: 2 byte value into 2 separate 1 byte values
« Reply #24 on: July 18, 2021, 08:09:20 am »
The alternative solution, based on arithmetic, may be be valid, but may as well contain a bug.

This is a very good point. Personally, I worked with hand-maintained bit shift fests until one day I hunted for a bug for hours; a bug which was caused by mistyping < instead of <<. Then I started thinking, there has to be a better way.

The problem with the arithmetic version, whether based on / % * or << >> | &, doesn't matter, is that it is error prone manual work. This is the preferred solution when the operations are small, simple and the number of such operations is small. Good for beginners, test programs, and so on. Just typecast everything using the stdint typedefs, and use a lot of parentheses everywhere.

This is also why I think the OP of this thread should go forward with janoc's approach. But it's not the generic solution.

Because when you start writing a full parser with dozens of data fields and you have 100 lines full of such bit shifting fest, it just falls apart. Then, you need indeed to look at the C standard to find out that interpreting any arbitrary data as an array of bytes, or char*, is indeed well defined; it's not only normal, it's also allowed by even the strictest views of language lawyers. Now if you extend this to a more generic pattern involving reverse operation, which is indeed required to take the advantage of the pattern, you need to understand the traps and their workarounds. Tough luck, C ain't easy. And practical C is different to "standard C". And microcontroller code is never perfectly portable anyway. Maybe you can accept the fact that you won't migrate the code from a little endian machine to a big endian one, or vice versa.

So really, I do see the bitshifting data partitioning as a beginner pattern. It's not bad, but it's not scalable. When you learn more about C, you start understanding how to avoid such error-prone process and have some better, but on more powerful tools, there are traps you need to know about.

Regarding alignment; most proper CPUs give ALIGNMENT ERROR interrupt (for example, busfault), making it easy to see what happened, why, and where, and fix it. Instead, a mistyped bitshift somewhere is completely hidden and only causes some certain parameter or field to act strangely. Almost impossible to debug; you may not even know you have a problem.
« Last Edit: July 18, 2021, 08:40:43 am by Siwastaja »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf