Skip to main content
EThom.3
Senior II
Jan 27, 2025 2:41 PM UTC
Question

Shifting left – a general C question

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.

This topic has been closed for replies.

17 replies

Andrew Neil
Super User
Jan 27, 2025 3:00 PM UTC

@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
Jan 27, 2025 3:06 PM UTC

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
Jan 27, 2025 8:20 PM UTC

> 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
Jan 28, 2025 1:18 AM UTC

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 Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
EThom.3
EThom.3Author
Senior II
Jan 28, 2025 8:12 AM UTC

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
Jan 28, 2025 8:39 AM UTC

@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
Mar 27, 2025 10:12 AM UTC

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
Apr 29, 2025 7:17 PM UTC

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 capacity. MISRA C++ Chair, MISRA C WG Member, Director The MISRA Consortium Limited (TMCL)