Skip to main content
EThom.3
Senior II
January 27, 2025
Question

Shifting left – a general C question

  • January 27, 2025
  • 5 replies
  • 1972 views

Hi,

I have a piece of CRC calculating code that I nicked from somewhere a couple of decades ago. I've been wondering about a few lines:

 *CRCVal ^= (*CRCVal << 8) << 4;
 *CRCVal ^= ((*CRCVal & 0xFF) << 4) << 1;

(CRCVal is a pointer to a uint16_t variable.)

What I'm curious about is the slightly weird left-shifting notation. Shouldn't it give exactly the same result if it was written like this?

 *CRCVal ^= (*CRCVal << 12);
 *CRCVal ^= (*CRCVal & 0xFF) << 5;

Does anyone have a hunch why the shifts are split up like this? Could it be something related to a specific compiler or device that handles half-byte shifts in a certain way?

By the way, it would be great if this forum had a "General programming" board. I prefer to ask questions here, as I think that the community has a nice vibe.

5 replies

Andrew Neil
Super User
January 27, 2025

@EThom.3 wrote:

code that I nicked from somewhere .


Well, nicking random code is always a bit risky ...

 


@EThom.3 wrote:

a couple of decades ago


Especially old random code!

 


@EThom.3 wrote:

Could it be something related to a specific compiler or device that handles half-byte shifts in a certain way?.


That would be my guess.

Impossible to know without actually asking the original author.

Even then it may have been misguided - compilers in the 2000s were already pretty good at optimising such things.

 


@EThom.3 wrote:

it would be great if this forum had a "General programming" board. .


I've moved it to the 'Others: hardware and software' section.

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
EThom.3
EThom.3Author
Senior II
January 27, 2025

Thanks Andrew.

While I do agree that nicking random code is risky, it was from a colleague I had at the time. I don't know the origin of it, but it has been used extensively during those decades, and works nicely. No problems at all.

I think I'll try both ways, and see if I can spot any difference in the compiled code.

Have a nice day!

TDK
Super User
January 27, 2025

> Does anyone have a hunch why the shifts are split up like this? Could it be something related to a specific compiler or device that handles half-byte shifts in a certain way?

Probably for readability. A shift by 8 and then 4 indicates a full byte shift and a further 4 bits. Whereas 12 might take longer to parse.

In any case, they're functionally identical and the compiler can probably optimize it into a single instruction in release configuration.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Tesla DeLorean
Guru
January 28, 2025

It would be interesting to know the context. The polynomial, the use case, and the MCU it's was originally developed for.

Can be a close stab if the true original is unknown.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
EThom.3
EThom.3Author
Senior II
January 28, 2025

The complete (now modified) function looks like this:

void CalcCRC(uint8_t Data, uint16_t *CRCVal) // XModem CRC (CCITT)
{
 *CRCVal = (uint8_t)(*CRCVal >> 8) | (*CRCVal << 8);
 *CRCVal ^= (uint8_t)Data;
 *CRCVal ^= (uint8_t)(*CRCVal & 0xFF) >> 4;
 *CRCVal ^= *CRCVal << 12;
 *CRCVal ^= (*CRCVal & 0xFF) << 5;
}

Polynomial: 0x1021

Initial value: 0

No reflection.

I don't know exactly what MCU it was made for, but most likely an 8-bit device. Possibly a PIC.

Or perhaps an 8051, if that even had a C compiler 20-30 years ago. Don't know. The only time I touched an 8051 was at the university, where it was programmed in assembly language. And I have no desire to ever use one again.

Andrew Neil
Super User
January 28, 2025

@EThom.3 wrote:

Or perhaps an 8051, if that even had a C compiler 20-30 years ago. .


Keil C51 was well-established 20-30 years ago.

Keil was established as an 8051 tools company long before ARM bought them.

https://en.wikipedia.org/wiki/Keil_(company)

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
EThom.3
EThom.3Author
Senior II
March 27, 2025

I just thought of something.

If this – quite old – code was indeed written for a PIC, it might have been written in an ancient MPLAB C compiler environment. Around the turn of the century, the MPLAB C17 compiler was not ANSI C compliant, had insane limitations, and was riddled with errors. If the CRC code was used in that environment, the doubled shifting operations might have been a work-around to get the code to compile correctly.

CTapp.1
Senior III
April 29, 2025

Reminds me of some code I had:

int someMeaningfulName;
int describeTheContent;

that was "improved" by someone to make it quicker to type the names: 

int smn;
int dtc;

 This was in a place where they had no backups or version control, so there was no easy way back :(

All posts are made in a personal capacityMISRA C++ ChairMISRA C WG MemberDirector The MISRA Consortium Limited (TMCL)