问题

我曾经很困惑,就是在两个编译单元当中,如何把一个单元中声明的struct结构引入到另外一个单元中来,折腾了很久,后来发现这位大神的留言

不是这么用的……

类型的定义和类型变量的定义不同,
类型定义只是描述一个类型,
是给编译器看的,
不会产生可执行代码。
变量定义是指在执行文件中真实得存在这么一块内容。

因为每个.c里都要写清楚类型定义很麻烦,
所以一般都把类型定义写在.h里
,而在.c里采用简单的写法,如struct A a;
这样定义变量,
不需把整个类型的描述再写一遍。

--------------------------------
所以,struct类型定义放到 ser.h里面,
ser.cpp 里加struct str st_r;
CmfcDlg.cpp加上#include "ser.h"
然后直接使用extern struct str st_r;

--------------------------------
楼主要有研究精神……
你先试下我上面说的……

我顿时发现自己是有多么的傻x.

说白了extern面向结构的语法,只针对对象的本身,而不包括结构,结构只是一个模板,是写给编译器看得。并不存在extern结构的说法,只能extern结构对象。

如果需要在两个编译单元内引入外部变量,那么你必须在两个文件当中引入这个结构,才能使用。

最科学的方法就是把结构写进一个.h文件,然后把它各自#include进每一个需要用到这个结构的文件当中。

示例,在a.c中声明结构chicken,随后声明一个叫jason的chicken对象。把jason引入b.c

a.c

struct chicken
{
char name[];
int age;
}; struct chicken jason = {
"jason",
};

b.c

#include <stdio.h>
struct chicken
{
char name[];
int age;
}; extern struct chicken jason; int main(void)
{
printf("%s\n", jason.name);//输出jason
}

这个例子有一个不合理的地方,就是两个文件都需要在各自上下文中声明结构chicken,一旦结构chicken有所改动,就会相当麻烦,你需要修改所有包含了该结构的页面。

所以这种情况下,通常会采取把结构声明语句挪出来独立作为一个头文件,之后用到的地方各自引用该头文件,下面是改动过的示例。

结构chicken被单独至于这个chicken.h文件当中:

struct chicken
{
char name[];
int age;
};

a.c:

#include "chicken.h"

struct chicken jason = {
"jason Chao",
};

b.c:

#include <stdio.h>
#include "chicken.h" //extern struct chicken jason;
struct chicken jason; int main(void)
{
printf("%s\n", jason.name);
}

结果是b.c会正常输出jason.name.

题外话

1.其实extern关键字是c的标识符声明中的[存储类修饰符]的一员,[存储类修饰符]包括extern、static、auto、register,在声明变量、函数、结构化数据时,extern标识符是默认的,也就是说,上面的例子即使不手动指明extern关键字,编译器也会默认把它当成extern关键字处理.

a.c

struct chicken
{
char name[];
int age;
}; struct chicken jason = {
"jason",
};

b.c

#include <stdio.h>
struct chicken
{
char name[];
int age;
}; struct chicken jason;//等价于extern struct chicken jason; int main(void)
{
printf("%s\n", jason.name);//输出jason
}

2.注意哦,变量只能初始化(赋予变量字面值)一次,就算外部变量也是一样哦,不然编译器会提示multiple definition of `xxx'

[C]关于extern与struct的更多相关文章

  1. 编译binutil包报错 error: array type has incomplete element type extern const struct relax_type md_relax_table[];

    安装lfs时编译binutils出错: ../../sources/binutils-2.15.91.0.2/gas/config/tc-i386.h:457:32: error: array typ ...

  2. C++extern关键字理解

    extern是一种"外部声明"的关键字,字面意思就是在此处声明某种变量或函数,在外部定义. 下面的示意图是我的理解. extern关键字的主要作用是扩大变量/函数的作用域,使得其它 ...

  3. php内核分析(二)-ZTS和zend_try

    这里阅读的php版本为PHP-7.1.0 RC3,阅读代码的平台为linux ZTS 我们会看到文章中有很多地方是: #ifdef ZTS # define CG(v) ZEND_TSRMG(comp ...

  4. C++学习笔记 知识集锦(二)

    1. 命名规范 2. 代码格式 3. QString的判断 4. 对象的判空 5. 隐式接口&显式接口 6. vector&string 7. static 8. const 9. v ...

  5. Android Bootloader LittleKernel的两篇文章 【转】

    转自:http://blog.csdn.net/loongembedded/article/details/41747523 2014-12-05 14:37 3599人阅读 评论(2) 收藏 举报 ...

  6. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

  7. linux kernel i2c底层代码跟踪

    其实跟上次跟的平台总线有关 在arch/arm/mach-mx6/board-mx6q_sabresd.c 文件中 static void __init mx6_sabresd_board_init( ...

  8. libevent源码分析(一)

    分析libevent的源代码,我的想法的是先分析各种结构体,struct event_base.struct event,然后是event_base_new函数.event_new函数.event_a ...

  9. Linux内核启动logo

    之前在分析samsung的fb驱动代码的时候,其中有一段代码是处理内核logo显示相关的,今天就内核logo这个话题来聊一聊! 一.处理内核logo显示相关的代码在哪? 回到samsung的fb驱动代 ...

随机推荐

  1. multiprocessing.Manager共享内存的问题记录

    问题:https://stackoverflow.com/questions/8640367/python-manager-dict-in-multiprocessing 使用 multiproces ...

  2. MDB数据类型注意事项

    在ArcGIS中,对MDB数据类型的支持较少,如下图: 当时当你打开Access软件的时候,你会发现文本类型,其实有很多种: 假如涉及到的字段类型是文本,而且又比较长,最好设置为“备注”

  3. ThinkJS 开发node后端 使用 简介

    ThinkJS 是一款面向未来开发的 Node.js 框架,整合了大量的项目最佳实践,让企业级开发变得如此简单.高效.从 3.0 开始,框架底层基于 Koa 2.x  实现,兼容 Koa 的所有功能. ...

  4. 三.HashMap原理及实现学习总结

    HashMap是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构.本篇主要是从HashMap的工作原理,数据结构分析,HashMap存储和读取几个方面对其进行学习总结.关于Hash ...

  5. 七、文件IO——I/O处理方式和文件锁

    7.1 I/O 处理方式 7.1.1 I/O处理的五种模型 阻塞I/O模型 若所调用的 I/O 函数没有完成相关的功能就会使进程挂起,直到相关数据到达才会返回.如 终端.网络设备的访问. 非阻塞模型 ...

  6. springboot-01 helloworld

    第一个springboot程序 新建maven项目,添加如下依赖: <?xml version="1.0" encoding="UTF-8"?> & ...

  7. 20155324 2016-2017-2 《Java程序设计》第3周学习总结

    20155324 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 定义类 要产生对象必须先定义类,类是对象的设计图,对象是类的实例.类定义时使用class关键 ...

  8. luogu P3721 [AH2017/HNOI2017]单旋

    传送门 \(Spaly:\)??? 考虑在暴力模拟的基础上优化 如果要插入一个数,那么根据二叉查找树的性质,这个点一定插在他的前驱的右子树或者是后继的左子树,可以利用set维护当前树里面的数,方便查找 ...

  9. Python文件打包成exe

    1. 安装pyinstaller pip install pyinstaller 2.如果有外部依赖包 将外部依赖包放到你的python安装的site-packages D:\Python27\Lib ...

  10. 模拟用户登录(获取cookie/实例化session)

    第一种方法:通过本地浏览器保存的cookie进行登陆 url1 = 'https://passport.cnblogs.com/user/signin?ReturnUrl=https%3A%2F%2F ...