【问题标题】:warning: ‘struct tag’ declared inside parameter list will not be visible outside of this definition or declaration void func(struct tag v);警告:在参数列表中声明的“struct tag”在此定义或声明之外将不可见 void func(struct tag v);
【发布时间】:2021-01-14 07:03:23
【问题描述】:

我正在尝试执行以下程序,但反过来编译器正在生成错误。我假设程序是正确的,并且我在程序的开头包含了函数原型。但是如果没有函数原型,程序就可以正常工作。 (即第一个函数定义和后来的主函数)。而且我想知道我的理解不正确的地方。

#include <stdio.h>

void func(struct tag v);

struct tag {
    int i;
    char c;
};
  
/*
void func(struct tag v)
{
    printf("%d %c\n", v.i, v.c);
    return;
}
*/

int main()
{
    /*struct tag {
        int i;
        char c;
    };*/
    struct tag var = {2, 's'};
    func(var);  

    return 0;
}

void func(struct tag v)
{
    printf("%d %c\n", v.i, v.c);
    return;
}

输出:

root@bhaskar:/home/bhaskar/Downloads/practice/cpractice/cindepth/struct# gcc p11_excer_1_4.c 
p11_excer_1_4.c:3:18: warning: ‘struct tag’ declared inside parameter list will not be visible outside of this definition or declaration
 void func(struct tag v);
                  ^~~
p11_excer_1_4.c: In function ‘main’:
p11_excer_1_4.c:17:7: error: type of formal parameter 1 is incomplete
  func(var);
       ^~~
p11_excer_1_4.c: At top level:
p11_excer_1_4.c:22:6: error: conflicting types for ‘func’
 void func(struct tag v)
      ^~~~
p11_excer_1_4.c:3:6: note: previous declaration of ‘func’ was here
 void func(struct tag v);
      ^~~~

【问题讨论】:

  • 记得在使用结构之前声明结构
  • 请使用一致的缩进样式。

标签: c struct parameters scope namespaces


【解决方案1】:

颠倒声明的顺序:

struct tag {
    int i;
    char c;
};

void func(struct tag v);

更好的是,将所有内容重新排序,这样您就不需要提前声明,您只需定义:

#include <stdio.h>

struct tag {
    int i;
    char c;
};
  

void func(struct tag v)
{
    printf("%d %c\n", v.i, v.c);
}


int main()
{
    struct tag var = {2, 's'};
    func(var);  

    return 0;
}

编译器需要在使用结构之前了解它们。它不能跳过以了解更多信息。

为避免过度复制,一般建议传入指向结构的指针,如:

void func(struct tag* v)
{
    printf("%d %c\n", v->i, v->c);
}

然后当调用时:

func(&var);

虽然struct 的大小相当小,但通常情况并非如此,因此熟悉此技术很重要。 struct 重达 1MB 或更多的情况并不少见,具体取决于内容,复制它可能会很痛苦。

也没有必要,也没有理由在 void 函数的末尾添加 return。这是默认行为。

【讨论】:

  • 你是对的@tadman。我只是简单地更改了函数原型和结构声明。但还有一个问题,为什么对于函数原型中的 int、char、float 等隐式数据类型不适用。
  • 那些基本类型总是被定义的。无需为它们导入声明。不过,这个列表相当短,甚至不包括像 uint8_tbool 这样不起眼的东西。
【解决方案2】:

这里有两个问题:

  • 如果结构用作类型,则应使用 typedef 声明。
  • 您需要先声明您的结构,然后才能实际引用它。

工作代码:

#include <stdio.h>

typedef struct{
    int i;
    char c;
}tag;

void func(tag v)
{
    printf("%d %c\n", v.i, v.c);
    return;
}

int main()
{
    tag var = {2, 's'};
    func(var);  

    return 0;
}

【讨论】:

  • 永远不要使用typedef struct { .... } foo;,前向声明将变得不可能。最好不要为 struct 使用 typedef 或为 structtypedef 使用相同的名称,如 typedef struct foo { ..... } foo; 或使用一种非常清晰和定义的方式从另一个创建一个名称。
  • 转发声明点正确。这样,结构没有名称,类型具有结构的名称。使用 typedef struct foo { ..... } foo;更安全。
  • 顺便说一句。有趣的用户号。
【解决方案3】:

根据 C 标准(6.2.1 标识符范围)

2 对于标识符指定的每个不同实体, 标识符仅在区域内可见(即可以使用) 程序文本称为其范围。指定的不同实体 相同的标识符要么具有不同的范围,要么具有不同的名称 空格。 有四种作用域:函数、文件、块和 函数原型。 (函数原型是一个声明 声明其参数类型的函数。)

所以函数的参数的type struct标签的声明

void func(struct tag v);

仅在函数原型声明中可见。

所以你声明的不完整类型struct tag 与结构函数后的声明不一样

void func(struct tag v);

struct tag {
    int i;
    char c;
};

你应该在声明函数之前声明结构。

考虑到 C 和 C++ 相对于这样的函数声明存在差异。

与 C++ 中的 C 相反,参数声明具有所谓的详细类型说明符,它在声明函数的范围内变得可见。

还请记住,通常最好通过指向它的指针通过引用传递结构类型的对象,而不是通过创建其副本的值传递它。

你可以写在你的程序里

struct tag {
    int i;
    char c;
};

void func( const struct tag *v);

//...

func( &var );

//...

void func( const struct tag *v)
{
    printf("%d %c\n", v->i, v->c);
}

(节点:你的函数定义中的return语句是多余的。)

【讨论】:

    猜你喜欢
    • 2021-06-29
    • 1970-01-01
    • 2022-06-14
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多