最近看了个答题,很好玩,对C结构体和C++类的理解有些帮助。
原题:C语言 结构体的赋值测试
题主的要求是在C语言结构体的赋值中使用如下方法,但是不能通过,问原因,更改方案。
#include <stdio.h>
#include <stdlib.h>
#define NUM 50
struct film
{
char name[NUM]; //电影的名称
int score; //电影的评分
};
typedef film FILM;
int main(void)
{
FILM movie;
movie = {"GoldedFather",10};
printf("the name is %s and the score is %d .\n",movie.name,movie.score);
return 0;
}
熟悉C语言的,一眼就能看出问题,这不是一个C的正常typedef,而是C++的,因为没有加struct,同时题主要用初始化的方法,但不在初始化的时候进行结构体赋值。
换句话说,如何用值列表在非初始化环境赋值给结构体。
当然,正常情况下,编译器是不允许这样做的。所以常规的解法是:
FILM movie = {"GoldedFather",10};
老老实实的按照C语言的规定,进行初始化赋值。
或者老老实实的进行成员赋值:
strcpy(movie.name,"GoldedFather");
movie.score=10;
更为根本的解决方法,也有人提出,用C++进行编译,没错,同样一段代码,用C编译叫结构体非初始化赋值,是非法的,但用C++就是类的值列表赋值,是合法的。
这个就是大家经常诟病的向下兼容,C++为了向下兼容C,让类的声明不仅可以用class,还可以用struct,于是在未标明究竟是C还是C++的时候,你无法判断同样一段代码是否合法。
从某种意义上,C++的只有public数据成员组成的struct类和C的struct结构体是一样的,成员的调用,成员赋值,成员使用都是一样的。区别只在定义和赋值时,C++似乎可以用更多的合法方法。
那么除了上述老老实实的方法,就没什么可行但不太建议的方法呢,有:
#include <stdio.h>
#include <stdlib.h>
typedef struct film
{
int a;
char b[10];
} FILM;
int main()
{
FILM movie;
movie = (FILM){1, "sdfa"};
}
其中的奥秘,估计老手一看便知,并且经常用来折磨代码维护人员,C的类型强制转换。
通过强制转换,C把一个值列表强制转为FILM结构体变量,那么一个结构体变量是可以赋值给另一个结构体变量的,这是合法的。
C语言太灵活了,灵活到近乎无法无天,强制转换这种语法,可以将任何类型转换为另一种任何类型,但是他把所有的责任都抛给了程序员。
一个灵活的C语言程序员的代码,在另一个人看,就是天书,当一个C++er在代码中混入C,或者相反,但没有注释,这将是一场灾难。
C不是面向对象的语言,在语言上讲,很大原因就是结构体无法完成类的一些效果,比如成员函数,比如私有成员,也就无法彻底的封装,使得库的使用者,永远可以用出乎意料的方式使用库构建者所构建的“类”。
最后总结,C语言和C++,不是一种语言,虽然兼容,但使用要格外小心,否则你真的无法知道你的程序究竟运行的是什么东西。