简体   繁体   中英

use macro to define two local variable but have the same address

Code as below:

#include"stdio.h"

#define MySTRING(ident, str) \
        ({\
                char str_##ident[16]; \
                memset((char *)str_##ident, 0x00, sizeof(str_##ident)); \
                memcpy(str_##ident, (str), strlen((str))); \
                str_##ident; \
        })

int main(int argc, char **argv)
{
        printf("%u, %u\n", MySTRING(qw, "1.1.1.1"), MySTRING(er, "2.2.2.2"));
}

Tetst result:

[root@cza temp]# gcc -O0 ./fly.c
[root@cza temp]# ./a.out
3959297344, 3959297360

[root@cza temp]# gcc -O2 ./fly.c
[root@cza temp]# ./a.out
2017090240, 2017090240

It seems like gcc optimistic make a difference on it.

The second result is not what I want, but in my app build template, O2 have been set.

I'd like to know the detail on why O2 make it difference, or is it a bug on GCC?

PS My colleague told me the prefix "volatile" can work.

Your code is a gcc extension called Statement Expression . The statements in the braces are executed, and the value of the final statement is the value of the expression. Any objects created are destroyed when the statement ends.

Being in a macro makes no difference; your code (update: the original code) is:

printf("%u, %u\n", ({ char ip_qw[16]; ip_qw; }), ({ char ip_er[16]; ip_er; }) );

When the ip_qw block ends, ip_qw is destroyed, so that memory is freed up for ip_er to use. This explains why it is possible to see the same address for both.

Your code is invalid because the printf function will access the contents of the 16-byte arrays after they have been destroyed.


Fortunately, Standard C has a solution. Objects that are returned by value are guaranteed to hang around until the end of the statement in which the function call was made. Arrays can't be returned by value, but structs can, so we can go:

 #include <stdio.h>
 #include <string.h>

 struct MS
 {
    char str[16];
 };

 struct MS make_MS(char const *str)
 {
    struct MS ms;
    strcpy(ms.str, str);
    return ms;
 }

 #define MySTRING(s) make_MS(s).str

 int main(int argc, char **argv)
 {
     printf("%s, %s\n", MySTRING("1.1.1.1"), MySTRING("2.2.2.2"));
 }

Notes:

  • Use angle brackets for standard includes
  • Use %p to print pointers (makes a difference on 64bit system)
  • Your macro with memset and memcpy was not any safer than strcpy ; in robust code you should change this strcpy to a snprintf(ms.str, sizeof ms.str, "%s", str); .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM