I am reading some C code and came across this declaration in the program:

unsigned char serv_ctr @0x0002;

Can someone point me to documentation, or explain what the "@0x0002" is for in the Mplab XC8 v1.35 C compiler?

  • 14
    \$\begingroup\$ I would guess that it is a compiler extension to place the variable at a specific address. \$\endgroup\$
    – Eugene Sh.
    May 21, 2019 at 18:36
  • 2
    \$\begingroup\$ the question might benefit the #mplab tag then, since it turns out this is Mplab-specific. \$\endgroup\$
    – sylvainulg
    May 22, 2019 at 7:34
  • \$\begingroup\$ Just to get it: Is this on topic on this site? I would think that this belongs to SO. Or is it okay to ask for micro controler programming here. This would make it a bit unclear where this questions should be. \$\endgroup\$
    – Kami Kaze
    May 22, 2019 at 12:28
  • 6
    \$\begingroup\$ @KamiKaze What topics can I ask about here? lists "the writing of firmware for bare-metal or RTOS applications" as on topic, and "Programming software for a PC" as off topic. Since this seems to be about embedded systems programming, it would appear at a glance to be on topic. That it might also be on topic on Stack Overflow doesn't by itself make it off topic here. \$\endgroup\$
    – user
    May 22, 2019 at 14:08

3 Answers 3


This is to specify an absolute address to place the variable at.
From the XC8 compiler manual page 27, section 2.5.2 Absolute Addressing:

Variables and functions can be placed at an absolute address by using the __at() construct
The 8-bit compilers have used an @ symbol to specify an absolute address


@ is a common non-standard extension to the C language which allows you to declare a variable at a specific address. It can be used for memory-mapped hardware registers etc. In which case the variable must also be declared volatile, so your example is incorrect.

Other compilers use something like __attribute__(section... or #pragma ..., all of it non-standard C.

The only rational reason (if any) why tool chains do this, is to enable register debugging on crappy debuggers. The non-standard syntax will ensure that the register becomes part of the linker output and debug info. Which in turn allows you to watch the register in the crappy debugger just as you can watch any other variable.

If you have a good debugger, it will have support and awareness of your specific MCU. Then you don't need non-standard crap in the C code, but you can write pure, portable standard C instead:

#define serv_ctr ( *(volatile uint8_t*)0x0002u )
  • 1
    \$\begingroup\$ While compilers are required to accept the latter form, implementations are allowed to map numbers to addresses in any way they see fit. Further, most compilers I've seen use @ notation target platforms with multiple memory spaces or other issues so that most things declared using @ notation would behave differently from anything that could be done without extensions. \$\endgroup\$
    – supercat
    May 22, 2019 at 15:09

A short extension:

This is no longer working since xc8 2.0 and up. You now had to write:

unsigned char serv_ctr __at(0x0002);

to put a variable (serv_ctr) at an absolute address (0x0002).

With XC8 2.0 it is possible to compile your old code using the @ syntax if you set the compiler settings to use "C90" format. The setting looks like this, it is under "XC8 Global Options" and is called "C standard".

  • \$\begingroup\$ Many other embedded systems compilers support the @ syntax too though, not just Mplab. \$\endgroup\$
    – Lundin
    Jun 3, 2019 at 8:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.