访问其范围之外的本地声明的结构

Acessing a locally declared struct outside of it's scope

我想将数据写入结构数组。结构本身在 main() 中声明和定义。我有 3 个函数需要写入、处理和读取数组中的数据。 我所能做的就是创建一个全局结构声明,然后将指针传递给它们。

是否可以不将结构声明设为全局?

相关代码贴在下面。

这是我在 main() 之外的结构声明

struct date
{
    int d;
    int m;
    int y;
};
struct stud
{
    int roll;
    char name[30];
    struct date dob;
    int P;
    int C;
    int M;
    float PCM;
    char flag_in;
    char flag_pro;
};

这些是函数定义。

 void getdata(struct stud *S)
    {
        scanf("%d", &(S->roll));
        scanf("%s", (S->name));
        //Similarly for dob, p, c, m
        (S->flag_in)='1';
        return;
    }

void process(struct stud *S)
{
    if(S->flag_in=='1')
    {
        S->PCM=(S->P + S->C + S->M)/3;
        S->flag_pro='1';
    }
}

void display(struct stud *S)
{
    for(int x=0; x<10; x++)
        if(S[x].flag_in=='1')
        {
            //printing the data to the console output
        }
}

这些是函数调用:

getdata(&S[i]);
process(&S[x]);
display(S);

Is it possible without making the structure declaration global?

不,任何函数都需要 struct 的定义可见(全局)才能使用。否则,从函数的角度来看,不可见的 struct 将是未定义的标识符。

局部结构在函数外的任何地方都不可见。

更重要的问题是,在本地化而不是全球化方面,您节省了什么?我想到的一件事是编译时间 可能 更快,因为如果在 header 中声明为全局,很多 TU 会不必要地看到它。

如果你的结构在 main() 中,那么这个结构的范围是 main() 的局部范围 由于结构是用户定义的数据类型,因此无法在您尝试时使用它,因为这种新类型仅在 main()

中可见

因此您定义的函数将不具有结构的可见性。

因此,为了处理这个问题,应该将结构设为全局。

所以你的问题的二元答案

Is it possible without making the structure declaration global?

您可以做的是在 main 中声明结构。并在调用函数时传递指针:

//this code is inside main
struct stud arr[10]; // create an array for the struct
display(arr); //pass the pointer to function

由于在函数之前调用了 main,因此数据不会被删除,并且会存在于其他函数的处理过程中,这些函数可以在它们之间传递指针。

虽然我建议如果功能不是用于一个目的(更改值、打印等...),则不要使用此方法。如果数据结构用作全局,则将其声明为全局。

我的印象是您不清楚 struct 类型的定义和该类型的实例之间的区别。

为了能够使用 struct 变量,您的函数必须查看完整的类型声明,以便编译器了解变量的结构以及访问不同的字段。但是他们没有必要这样看变量声明。通过作为参数传递的指针可以毫无问题地访问该变量。

不想将程序的其他部分暴露给类型的内部结构是完全正确的。

C 非常适合以相当优雅的方式做到这一点。

称之为X.h

//Declaration of X as pointing to an incomplete struct XS.
//This says there's such a thing as a struct XS but not how it is laid out or even how big it is.
//It also says X is a short-hand for a pointer to a mysterious XS structure. 
typedef struct XS* X;

//Creates an X and returns a pointer to it. Remember to call destroyX(.) exactly once - later.    
X createX(void);
//Does something with X and returns some number.
int doXThing(X x);

//Destroys an X. Must be called exactly once for each return value from createX().
void destroyX(X x);

这是 prog.c(包含您的 main(.) 函数)。

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

//Now we actually define that mysterious structure.
//Other translation units will not see this.
struct XS {
    int v;
} ;

//Here we have size and layout so we can actually implement it.

X createX(void){
    X x=malloc(sizeof(struct XS));//Explicit allocation of 'implementation struct'.
    if(x==NULL){
        return NULL;//malloc(.) failed.
    }
    x->v=0;
    return x;
}

int doXThing(X x){
    return (x->v)++;
}

void destroyX(X x){
    free(x);
}

int main(void) {
    X x=createX();

    printf("%d\n",doXThing(x));
    printf("%d\n",doXThing(x));
    printf("%d\n",doXThing(x));

    destroyX(x);

    return 0;
}

请注意,使用 #include "X.h" 的其他模块看不到结构的布局。 好处是实现可以正常更改而无需重新编译 - 只需重新链接即可。 不利之处在于,如果无法访问 X 的大小和布局,那些 'using' 模块需要将所有工作委托给一个可以执行的模块! 这意味着所有 X 都必须来自免费商店(或实现模块内的静态池..)。

这个模型真的很常见,也很强大,因为它允许完全抽象和数据隐藏。

如果你愿意做大量的演员工作,你甚至不需要'reveal'名字XS

typedef XSHandle* X;

甚至

typedef unsigned short* X; //Little used type... Illegal but works on most platforms - check your documentation of use char (bare, signed or unsigned).

但不要陷入:

typedef void* X;

在 C 中。void* 的转换非常混乱,你会惹上麻烦的! 然而,C++ 在这方面的表现要好得多。

PS: 把实现和main(.)放在同一个翻译单元是不正常的。 在一个小项目中这并没有错,但是在一个小项目中进行如此多的抽象是不正常的。

PPS: A 表示此方法提供了非常高程度的 OO 编程。有趣的是,Stroustrup 做出了有记录的设计决定,不对 C++ 中的所有 类 执行此操作,因为它具有固定且不可避免的开销,他给自己一个 'zero-overhead principle' 并希望提供一种方法 'mixing' 直接访问对象布局的抽象(作为局部变量分配,直接访问成员,内联函数,...)。

我认为他做出了正确的决定,作为 C++ 预期用途的语言级别决定。在适当的情况下,这并不会使它成为糟糕的设计模式。