理解C名称空间

理解C名称空间,c,namespaces,C,Namespaces,引用 在C中,有两种不同类型的名称空间:一种是struct/union/enum标记名的名称空间,另一种是typedef名称的名称空间 name.c $ cat name.c #include<stdio.h> typedef long long long2; int long2 () { return 4; } int main() { printf("hello, world!"); return 0; } $ gcc name.c -o name

引用

在C中,有两种不同类型的名称空间:一种是struct/union/enum标记名的名称空间,另一种是typedef名称的名称空间

name.c

$ cat name.c
#include<stdio.h>

typedef long long long2;

int long2 () {
    return 4;
}

int main() {

    printf("hello, world!");
    return 0;
}
$ gcc name.c -o name
name.c:4: error: 'long2' redeclared as different kind of symbol
name.c:3: error: previous declaration of 'long2' was here
$
$ cat name2.c
#include<stdio.h>

int four() {
    return 4;
}

struct dummy {
    int member;
};

int main() {

    struct dummy four;
}

$ gcc name2.c -o name2
$ 
$cat name.c
#包括
typedef-long2;
int long2(){
返回4;
}
int main(){
printf(“你好,世界!”);
返回0;
}
$gcc name.c-o name
name.c:4:错误:“long2”重新声明为不同类型的符号
name.c:3:错误:前面的“long2”声明在此
$
name2.c

$ cat name.c
#include<stdio.h>

typedef long long long2;

int long2 () {
    return 4;
}

int main() {

    printf("hello, world!");
    return 0;
}
$ gcc name.c -o name
name.c:4: error: 'long2' redeclared as different kind of symbol
name.c:3: error: previous declaration of 'long2' was here
$
$ cat name2.c
#include<stdio.h>

int four() {
    return 4;
}

struct dummy {
    int member;
};

int main() {

    struct dummy four;
}

$ gcc name2.c -o name2
$ 
$cat name2.c
#包括
int-four(){
返回4;
}
结构虚拟{
国际会员;
};
int main(){
结构虚拟四;
}
$gcc名称2.c-o名称2
$ 
我试图理解C名称空间冲突

  • 在第一种情况下,为什么会有冲突?函数是否也属于typedef命名空间

  • 在第二种情况下,为什么根本没有冲突?函数和变量都被命名为四。为什么编译器允许这样做?
    &four
    应该如何解决


C有四个不同的标识符名称空间:

  • 标签名称(转到类型)
  • 标记(结构、联合和枚举的名称)
  • 结构和联合的成员(每个结构/联合有一个单独的名称空间)
  • 所有其他标识符(函数名、对象名、类型(def)名、枚举常量等)
另见C99 6.2.3

所以你的两个问题可以回答为:

  • 是的,函数名和typedef名共享相同的名称空间
  • 没有冲突,因为编译器将使用范围规则(函数或对象名)。main中的标识符被认为是全局函数名的阴影,如果您将警告级别设置得足够高,编译器将对此发出警告

  • 您的第二个示例没有显示“无冲突”。有冲突!试试这个:

    #include <stdio.h>
    int four(void) { return 4; }
    struct dummy { int member; };
    int main(void) {
        struct dummy four;
        four.member = four();
    }
    
    #包括
    int-four(void){return 4;}
    结构虚拟{int member;};
    内部主(空){
    结构虚拟四;
    four.member=four();
    }
    
    现在这个

    #include <stdio.h>
    int four(void) { return 4; }
    struct dummy { int member; };
    int main(void) {
        int (*fx)(void) = four; /* "save" function */
        struct dummy four;     /* hide it         */
        four.member = fx();    /* use "hidden" fx */
    }
    
    #包括
    int-four(void){return 4;}
    结构虚拟{int member;};
    内部主(空){
    int(*fx)(void)=四;/*“保存”函数*/
    struct dummy four;/*隐藏它*/
    four.member=fx();/*使用“隐藏”fx*/
    }
    

    在第二个示例中,变量
    four
    隐藏函数
    four()

    ,但示例中的关键点不是名称空间,而是名称的范围

    name.c中,两个
    long2
    都是“普通标识符”(共享相同的名称空间),并且它们都定义在相同的范围内,因此存在冲突。(C99§6.7/3)


    如果name2.c,则局部变量
    four
    的作用域比函数
    four
    更深,因此该变量隐藏函数
    four
    (C99§6.2.1/4)。

    快速回答您的两个问题

    问题1。在第一种情况下,为什么会有冲突?函数是否也属于typedef命名空间

    A1。是的,函数和类型定义类型的标识符共享相同的命名空间。所以有冲突

    问题2。在第二种情况下,为什么根本没有冲突?函数和变量都被命名为四。为什么编译器允许这样做?应该如何解决&4

    A2。第二个示例中没有冲突,即使名为四的两个标识符属于相同的标识符namesapce,即
    普通名称空间
    。因为main中的变量标识符4在函数范围中,而文件范围中的函数标识符4在中。因此,后者作为基本范围规则被前者所隐藏。如果像下面这样将变量4移动到文件范围(全局),您将看到一个错误

    。。。
    结构虚拟四;//错误!有一个先前的定义
    //在此文件范围内(全局)。
    int main(){
    //struct dummy four;//注释掉。
    }
    

    实际上,有四种不同的标识符名称空间:标签、标记、成员和普通。您可以在

    结构/联合/枚举是否共享一个命名空间中找到有关它们的详细信息?i、 例如,
    struct
    union T
    能很好地结合在一起吗?