【问题标题】:Is 'redefining' variables in statement expressions safe?在语句表达式中“重新定义”变量是否安全?
【发布时间】:2012-04-27 12:44:20
【问题描述】:

我的问题是关于statement expressions,它是作为 GNU C 的扩展添加的。考虑以下代码:

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    int i = 0;
    printf("%d\n", i);

    {int i = 1;printf("%d\n", i);}

    printf("%d\n", i);
    return EXIT_SUCCESS;
}

编译 (gcc -Wall -std=gnu99 lala.c -o lala) 并运行将产生:

0
1
0

这种做法(使用扩展)相当普遍,尤其是在 Linux 内核中的 container_of

#define container_of(ptr, type, member) ({ \
                const typeof( ((type *)0)->member ) *__mptr = (ptr); 
                (type *)( (char *)__mptr - offsetof(type,member) );})

与这种情况类似,我想定义一个宏来声明一个局部变量并对其进行处理。但是,我希望这样做不会污染当前范围内可用的变量名,并避免可能的重新定义。我无法在文档中找到关于在重新定义的情况下范围界定如何发生的确切信息。

在上述情况下,编译器不会发出有关重新定义的警告。我的问题是我是否可以依靠语句表达式内部的变量不会影响外部范围内的同名变量这一事实?

【问题讨论】:

  • 不允许声明名称以两个下划线开头的变量。
  • 你的用法不只是复合语句吗?根据链接的文档,它必须是一个语句表达式,它必须用括号括起来
  • @msam: 是的,但我想用括号定义一个宏

标签: c gcc c99 gnu99


【解决方案1】:

当然这是安全的,这就是作用域的用途。

(正如 dreamlax 在他的评论中指出的那样,带有两个下划线的标识符是为实现(编译器、库、托管环境...)保留的,所以你不应该使用它们。)

【讨论】:

  • 对,愚蠢的问题:P 我应该知道的关键字是“影子变量”,我以前从未遇到过(可能是因为一般人都避免使用它们)。
【解决方案2】:

关于范围

来自 3.1.2.1 ANSI C(类似 C99 中的 6.2.1):

如果声明者或 声明标识符的类型说明符出现在块内或 在函数定义的参数声明列表中, 标识符具有块作用域,在 } 处终止 相关块

...

如果外 词法相同标识符的声明存在于同一 名称空间,它是隐藏的,直到当前范围终止,之后 它再次变得可见。

所以假设编译器是兼容的,你应该能够假设表达式内的变量不会影响外部范围内的变量

【讨论】:

  • 只发布了上面的答案,因为它太长了,不能成为评论
猜你喜欢
  • 2018-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-01
  • 2013-10-07
  • 2020-04-04
相关资源
最近更新 更多