我正在学习C语言,最近学会了如何使用C编写面向对象程序。除了用于创建新类的结构类型的名称外,大部分内容对我来说并不难理解。
我的教科书使用struct dummy_t
作为正向声明,使用typedef struct {...} dummy_t
作为其定义。据我所知,这是两种不同的类型,因为前者是struct dummy
类型,后者是struct
类型,没有名称标签,但教科书中的示例代码运行良好。
因此,我特意修改了示例代码,以便结构名称的差异更加清晰。下面是我尝试过的代码行。
//class.h
struct test_a;
struct test_a * test_init(void);
void test_print(struct test_a*);
//class.c
#include <stdio.h>
#include <stdlib.h>
typedef struct dummy{
int x;
int y;
} test_b;
test_b * test_init(void){
test_b * temp = (test_b *) malloc(sizeof(test_b));
temp->x = 10;
temp->y = 11;
return temp;
}
void test_print(test_b* obj){
printf("x: %d, y: %dn", obj->x, obj->y);
}
//main.c
#include "class.h"
int main(void){
struct test_a * obj;
obj = test_init();
test_print(obj);
return 0;
}
// It printed "x: 10, y: 10"
正如您所看到的,我使用struct test_a
进行正向声明,使用typedef struct dummy {...} test_b
进行定义。我想知道为什么我没有得到编译错误,它工作。
我想知道为什么我没有得到编译错误
编译main.c时,编译器会通过类.h的前向声明得知有一个签名为struct test_a * test_init(void);
的函数
编译器不能做任何事情,只能相信这一点,即不会发出任何错误,也不会发出任何警告。
编译class.c
时,没有正向声明,只有函数定义,即没有错误,没有警告。
最好将.h文件包含到相应的.c文件中。如果在类.c中有一个#include "class.h"
,编译器就能够检测到不匹配。
。。它起到了的作用
发生的是:
-
指向test_b的指针被分配给指向test_A变量的指针
-
然后将变量作为参数传递给一个函数,该函数期望指向test_b 的指针
因此,一旦使用了指针,它就会像创建时一样使用(即作为指向test_b的指针(。在两者之间,您只是存储在另一个指针类型的变量中。
可以吗否
将指向一个类型的指针存储在为另一个指针类型定义的对象中是不好的。这是未定义的行为。在这种情况下;刚好工作";。在现实生活中;刚好工作";在大多数系统上,因为大多数系统对所有类型使用相同的指针布局。但根据C标准,这是未定义的行为。
它之所以"有效",是因为您没有在class.c
中包含class.h
。所以编译器看不到实现与声明不匹配。
正确的方法是(但为了清晰起见,没有typedef(:
// class.h
struct test_a;
struct test_a* test_init(void);
//class.c
#include "class.h"
struct test_a {
int x;
int y;
};
struct test_a* test_init(void)
{
...
}
头文件中的struct test_a
使得名称test_a
对于编译器来说是一个结构体。但由于它现在不知道结构中的内容,您只能使用指向这样一个结构的指针。
成员是在实现文件中定义的,并且只能在那里使用。
如果你想使用typedef:
// header
typedef struct test_a_struct test_a;
test_a* test_init(void);
//implementation
struct test_a_struct {
int x;
int y;
};
test_a* test_init(void)
{
...
}