Is there really any difference between C and Embedded C

Thread Starter

Embededd

Joined Jun 4, 2025
143
Hi, I'm trying to understand the difference between normal C and Embedded C.

Here's what I know:

Normal C is what we use on computers with Windows or Linux. It works with the operating system to do things like print to the screen or read files.

Embedded C is what we use for microcontrollers like AVR or ARM chips. These often don't have an operating system, so we write code that talks directly to hardware - like turning LEDs on/off or reading buttons.

But I'm confused because some microcontrollers (like Raspberry Pi) actually run Linux. If I write normal C programs on a Pi, is that still Embedded C?

I think it's probably the same C language, just used differently with specific hardware. Is there really any difference between C and Embedded C, or is it just the environment where we use the C language that makes the difference?
 

nsaspook

Joined Aug 27, 2009
16,270
There is embedded software that can be written in C. There are compilers with code targets mainly used for embedded applications like microcontrollers but I write embedded applications software in GCC on a x64 Linux platform that normally run on ARM64 Linux platforms using the GCC cross compiler.

Embedded is the application, not the language or hardware. For me usually, half is kernel level driver code and the other half is embedded applications at the user OS level for a typical system.

Kernel level
https://github.com/nsaspook/mqtt_comedi/blob/fixes/daq_bmc/daq_bmc.c

Applications level
https://github.com/nsaspook/mqtt_comedi/blob/main/bmc/bmc_mqtt.c

Both are using GCC.
 

Thread Starter

Embededd

Joined Jun 4, 2025
143
The language is the same, but the libraries are different.
Thanks for clarifying that it's the same C language with different libraries. That helps, but I'm still curious about some practical differences I've noticed:

  1. Behavior Differences:
    For example, on my PC, printf("Hello") just works, but on my Arduino I have to configure UART registers first. Is this purely a library difference, or are there underlying compiler/language tweaks enabling this?
  2. Special Keywords:
    I keep seeing volatile and bit manipulation code in embedded programs. Are these standard C features just used more in embedded, or are they added/enhanced by embedded compilers?
 

nsaspook

Joined Aug 27, 2009
16,270
It's all the same basic compiler, just a different level of abstraction.
For the same embedded project on Linux, this is some of the hardware firmware C source for a PIC18 device for the Linux kernel on the ARM machine.

I use a version of printf for diagnostic messages to the CLCD screen. My lib allows you to print to several 'virtual' screens and then select the one you with to view on the 20X4 character screen. Typical embedded stuff.
https://github.com/nsaspook/mqtt_comedi/blob/fixes/Q84/bmc_slave.X/main.c

Using volatile for variables that will up updated in a ISR and used out of the ISR. Volatile is a compiler command to change the way it optimizes variables. With a non-optimizing compiler, you don't need it.
Bit level operations are implementation defined. On a 32-bit word machine you might be able to get/set/clear bits or create 32-bit bit-mapped structures in C. On a 8-bit machine like the PIC18 that would be limited to 8-bit words.

https://github.com/nsaspook/mqtt_comedi/blob/fixes/Q84/bmc_slave.X/slaveo.h
https://github.com/nsaspook/mqtt_comedi/blob/fixes/Q84/bmc_slave.X/slaveo.c

https://forum.allaboutcircuits.com/threads/home-assistant-devices-and-uses.206323/post-1985856


The main thing and important thing about Embedded C is that you need to be good in hardware and software design. It's a tricky balance to optimize the mix for any non-trivial project. I like the classic PIC18 8-bit devices for things that touch the wire because they are robust to the sorts of noise that will kill most of the 32-bit cheap modules without any additional external protection.

https://forum.allaboutcircuits.com/threads/home-assistant-devices-and-uses.206323/post-1986384
 
Last edited:

Futurist

Joined Apr 8, 2025
725
Thanks for clarifying that it's the same C language with different libraries. That helps, but I'm still curious about some practical differences I've noticed:

  1. Behavior Differences:
    For example, on my PC, printf("Hello") just works, but on my Arduino I have to configure UART registers first. Is this purely a library difference, or are there underlying compiler/language tweaks enabling this?
  2. Special Keywords:
    I keep seeing volatile and bit manipulation code in embedded programs. Are these standard C features just used more in embedded, or are they added/enhanced by embedded compilers?
The C language is quite old now and has changed in many way since the first versions of it. It was originally created to help in writing systems and utility code like an operating system. At the time (early 1970s) there were few options for writing system oriented code, most languages were targeting things like business or scientific computing problems and OS code was written in assembly language by manufacturers. Writing an OS was unheard of, it was the stuff of academic research but vendors and users all focused on real world business/science problems (hence the prevalence of COBOL and Fortran).

Although the PL/I language was foundational to developing Multics (the first OS written in a high level language), that was a large corporate project with a big team and back then PL/I was challenging to implement compliers for (The Multics compiler had a team of its own). PL/I was well suited (in some ways but not all) to writing an OS but was inaccessible to all intents and purposes.

So C was created and simplicity of a compiler was one of the core goals, so the nature of C itself is rooted partly in the goal of ease of implementation, we see evidence of this still in (for example) the need to forward declare function signatures (aka "prototypes" in C parlance) and the absence of a string data type, these and other characteristics made a compiler easier to write back then (also a large compiler itself might be hard to run on a small minicomputer simply because it was too big for the machine's memory).

Things to note here:

1. The language has long been standardized and there are several standards supported today.
2. The language has a large number of "implementation defined" behaviors.
3. The language has many vendor extensions, Microsoft C and Intel C for example might conform to the same standard but also might contain extension keywords and behaviors unique to each vendor.

Having said that C is C and the differences that do exist are rarely syntactic in nature, more often the differences are this or that keyword and stuff.

It is true to say that C is not very portable, it scores poorly on portability (unless the code is written with great discipline by avoiding vendor extensions and minimizing implementation defined behaviors).
 
Last edited:

geekoftheweek

Joined Oct 6, 2013
1,429
  1. Behavior Differences:
    For example, on my PC, printf("Hello") just works, but on my Arduino I have to configure UART registers first. Is this purely a library difference, or are there underlying compiler/language tweaks enabling this?
  2. Special Keywords:
    I keep seeing volatile and bit manipulation code in embedded programs. Are these standard C features just used more in embedded, or are they added/enhanced by embedded compilers?
The difference in printf is mainly due to the fact on a PC printf defaults to the "standard output" which is your display and has a standard method of getting the text to the display. In GNU C you can open say your UART of your PC and have it return a file descriptor that you could then use fprintf() to write to the UART. Since the Arduino doesn't have a display it is going to default to the UART to "display" text using printf. The reason you have to configure the UART first is just the way the library is written. ESP devices are set up for 115200 baud, 8 bit, no parity in the OS, but you still have to initialize the serial port to some extent before you can write to it. Every device is going to be a little bit different in what steps you have to take.

Bit manipulation is mainly what makes microcontrollers do what they do. Every pin, peripheral, and feature works by manipulationg bits in memory. One bit at one location will chance the pin from input to output, and another bit at another location will make the output high or low. Another bit at yet another location will tell you the input state of the pin. It's the same as it is with any other form of C, but since it directly affects what a microcontroller does you will see lots more of it. At the kernel level in your PC there is about the same amount of bit manipulation. You just never see it.
 
Top