Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
839 views
in Technique[技术] by (71.8m points)

abstract class - Accessing a struct defined in another c file?

I am trying to access a struct defined in one c file from another c file. The issue is that I cannot use the extern keyword nor can I defined the struct in the header file. How do I access the struct defined in abstract.c inside use_abstract.c? Here is a minimally producible example:

abstract.c

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

typedef struct s_strukt {
    int x;
} strukt;

strukt* create_struct() {
    strukt* s = malloc(sizeof(strukt));

    return s;
}

abstract.h

#ifndef H_ABSTRACT
#define H_ABSTRACT
struct s_strukt;

#endif

use_abstract.c

#include <stdio.h>
#include "abstract.h"

int main() {

    strukt *s = create_struct();
    s->x = 0;

    return 0;
}

Executing the following results in errors gcc use_abstract.c abstract.c:

use_abstract.c:6:5: error: use of undeclared identifier 'strukt'; did you mean 'struct'?
    strukt *s = create_struct();
    ^~~~~~
    struct
use_abstract.c:6:5: error: declaration of anonymous struct must be a definition
use_abstract.c:6:5: warning: declaration does not declare anything [-Wmissing-declarations]
use_abstract.c:7:5: error: use of undeclared identifier 's'
    s->x = 0;
    ^
1 warning and 3 errors generated.
question from:https://stackoverflow.com/questions/65833097/accessing-a-struct-defined-in-another-c-file

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are a few ways of tackling this particular issue, depending on what you're trying to do.

First, your code seems to be conflating the structure name struct s_strukt with the typedef name strukt. In general, the typedef would live in abstract.h, where it would be available to both client code and to the implementation in abstract.c (and I think that, in general, having a type name that is one letter different from -- and pronounced the same -- as an existing C keyword is going to lead to confusion and dismay).

If your goal is clear separation between interface and implementation, you can use what are called "opaque structures". This is what you get when you have a type that references a structure the definition of which isn't visible to the calling code (for example, the FILE type used by fopen/fclose/read/write, etc).

In abstract.h, you would have:

#ifndef H_ABSTRACT
#define H_ABSTRACT

typedef struct s_strukt strukt;

strukt *create_strukt(void);
#endif

And in abstract.c, you would have:

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

#include "abstract.h"

struct s_strukt {
    int x;
};

strukt *create_strukt() {
    strukt *s = malloc(sizeof(strukt));
    return s;
}

Given the above, you could write use_abstract.c like this and it would compile without error:

#include <stdio.h>
#include "abstract.h"

int main() {
    strukt *s = create_strukt();

    return 0;
}

But there's a problem! Because strukt is an opaque type, if you try to do this in use_abstract.c:

s->x = 0;

It will fail:

use_abstract.c: In function ‘main’:
use_abstract.c:8:6: error: invalid use of incomplete typedef ‘strukt’ {aka ‘struct s_strukt’}
    8 |     s->x = 0;
      |      ^~

A typical solution for this is to implement routines in abstract.c to get/set values in the opaque structure. E.g., make abstract.h look like this:

#ifndef H_ABSTRACT
#define H_ABSTRACT

typedef struct s_strukt strukt;

strukt *create_strukt(void);
void strukt_set_x(strukt *s, int value);
int strukt_get_x(strukt *s);

#endif

And abstract.c look like this:

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

#include "abstract.h"

struct s_strukt {
    int x;
};

strukt *create_strukt() {
    strukt *s = malloc(sizeof(strukt));
    return s;
}

void strukt_set_x(strukt *s, int x) {
    s->x = x;
}

int strukt_get_x(strukt *s) {
    return s->x;
}

And then write use_abstract.c like this:

#include <stdio.h>
#include "abstract.h"

int main() {
    int val;

    strukt *s = create_strukt();
    strukt_set_x(s, 0);
    val = strukt_get_x(s);
    printf("val is: %d
", val);

    return 0;
}


But what if you don't want to use an opaque structure? Then you would write abstract.h like this:

#ifndef H_ABSTRACT
#define H_ABSTRACT

typedef struct s_strukt {
    int x;
} strukt;

strukt *create_strukt(void);

#endif

Because the structure definition is now in abstract.h, where it's exposed both to the implementation in abstract.c and the client code in use_abstract.c, we no longer need getter/setter functions, because code in use_abstract.c can access structure members directly. With the above, abstract.c would look like:

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

#include "abstract.h"

strukt *create_strukt() {
    strukt *s = malloc(sizeof(strukt));
    return s;
}

And use_abstract.c would look like:

#include <stdio.h>
#include "abstract.h"

int main() {
    strukt *s = create_strukt();
    s->x = 0;
    printf("x is: %d
", s->x);

    return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...