2
\$\begingroup\$

I am trying to understand why I get the following warning

#include <xc.h>

int main (void)
{
     int __attribute__((address(0x3000))) x;


     while(1);

     return 0;
 }

PIC24_Attributes.c:13:5: warning: ignoring address attribute applied to automatic x

I know __attribute__address((address(0x3000))) x means store the variable of type int x in DATA SPACE address 0x3000

When I download the program, and debug it, I see that the address of x is 0x856

but when I put it globally the warning disappears, and when I debug, the address of x is 0x3000.

I googled the warning I got, and I found someone with the same warning as me, but with the space attribute instead (http://www.microchip.com/forums/m351172.aspx)

From what I understood was __attribute__ only works for static variables, and automatic variables (don't know why it is automatic, it is an int) are allocated dynamically.

Can someone explain this please, as I understand that `attribute((address(...)))' means store the following variable at a certain address.

  • Microncotroller: PIC24FJ1024GB610 (Microchip)
  • Debugger: PKOB (Explorer 16/32 Development Board)
\$\endgroup\$
3
  • 7
    \$\begingroup\$ I think your question is more appropriate for Stackoverflow. \$\endgroup\$
    – Oskar Skog
    Commented Jul 22, 2017 at 14:03
  • 2
    \$\begingroup\$ XC16 users guide section 2.5.2 Absolute Addressing: Variables and functions can be placed at an absolute address by using the __at() construct. Stack-based (auto and parameter) variables cannot use the __at() specifier... 16- and 32-bit compilers have used the address attribute to specify an object’s address. \$\endgroup\$ Commented Jul 22, 2017 at 22:25
  • \$\begingroup\$ that wouldn't have even needed reading the compiler manuals to be answered on Stack Overflow... \$\endgroup\$ Commented Jul 23, 2017 at 20:53

3 Answers 3

4
\$\begingroup\$

Automatic refers to the C concept of automatic storage duration. In C, there are chiefly 2 different storage durations for objects: static (not to be confused with the static keyword, which is a storage-class specifier) and automatic. An object shall retain its last stored value and will be stored at a constant address for the entire duration of its lifetime.

Static storage duration means "the duration of the entire program" - that is, from before entering the main the first time up to after exiting it.

Automatic storage duration is for objects "declared with no linkage and without the storage-class specifier static" - the no linkage means that they're not declared globally - they're declared/defined within a block, and not declared with storage-class specifier extern. Their lifetime is chiefly to the end of the block.

Now in your program,

#include <xc.h>
int main (void)
{
     int __attribute__((address(0x3000))) x;
     while(1);
     return 0;
}

Since the declaration-definition int x; it has neither the extern nor static storage-class specifier, it defines an int object of automatic storage duration within the main function. Each time the main function is entered, a new distinct object must be allocated. C allows the main function to call itself recursively too, so clearly x simply cannot be at a fixed address here. In fact, on many computer architectures x might not even reside in memory at all - it might be in a register, or optimized out completely.


It makes sense only to have an object that has static storage duration, as opposed to automatic storage duration, to be located at a fixed address. In addition to declaring this at the file scope:

int __attribute__((address(0x3000))) x;
int main(void) { ... }

which would make x accessible everywhere within the file, you can also make the identifier private to the main function, but still retain the static storage duration, by using the static storage-class specifier:

int main(void) { 
    static int __attribute__((address(0x3000))) x;
    ... 
}

Now, the identifier x is not visible outside the main function; and exactly only one x is defined, and its storage duration is static, which means that it is for the entire duration of the program - as its storage duration is not automatic, but it will have a fixed address for the entire runtime of the program, the compiler can be asked to locate it at an alternate address.

\$\endgroup\$
10
\$\begingroup\$

x is a local variable. It doesn't necessarily even get a storage address. So, you can't necessarily assign an address to it.

Make x global.

"automatic" is the storage type of a variable, not the data type, so it being int is orthogonal to it being static or automatic.

It's a bit surprising your debugger sees an address for the main-local x at all – it'd be totally appropriate of the compiler to see that x, analyze where it's used, see it's used nowhere, and simply don't assign any location at all.

For example:

test_temp_storage.c

/* test_temp_storage.c */
int main()
{
  int x;
  while(1);
  return 0;
}

building, with -Os, something that every sensible human would do to a microcontroller-targetting compiler (optimizing for code size):

$> clang -g -Os -o test test_temp_storage.c

debugging, break before entering while loop:

$> gdb test
(gdb) break test_temp_storage.c 
Breakpoint 1 at 0x400490: file test_temp_storage.c, line 5.
(gdb) run
Starting program: /home/marcus/src/scratch/test 

Breakpoint 1, main () at test_temp_storage.c:5
5     while(1);
(gdb) print x
$1 = <optimized out>
(gdb) print &x
Can't take address of "x" which isn't an lvalue.

As you can see, there's no x here in existence.

\$\endgroup\$
4
  • \$\begingroup\$ I am surprised that you see the compiler doesn't assign an address to a local variable (it might be out of scope, but have an address), in ANSI C/C++, and PIC24 C (C for Microchip microcontroller), if that is your case, then how come we can create pointers that can point to an address of a variable \$\endgroup\$ Commented Jul 22, 2017 at 14:08
  • \$\begingroup\$ @Adam see my edit \$\endgroup\$ Commented Jul 22, 2017 at 14:23
  • 4
    \$\begingroup\$ @Adam -- if you create a pointer to x you have to take the address of x, and when you do that, the compiler won't optimize it out. \$\endgroup\$ Commented Jul 22, 2017 at 14:25
  • 1
    \$\begingroup\$ @Adam -- that's because if there are no addresses taken of x, the compiler can allocate it into a CPU register instead \$\endgroup\$ Commented Jul 22, 2017 at 22:24
6
\$\begingroup\$

To understand why you cannot assign the address of an 'automatic' local variable, consider recursion.

int treesum(const tree *x)
{
    int sum = x->value;
    if (x->left)
        sum += treesum(x->left);
    if (x->right)
        sum += treesum(x->right);
    return sum;
}

Each recursive invocation of treesum must have its own copy of the variable sum. Therefore, they cannot all be assigned the same address.

The rule applies to all automatic variables, not just automatic variables in functions called recursively, because the compiler doesn't always know whether a function is going to be called recursively; it could be that f calls g calls h calls f, and h is defined in another source file.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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