ONVIF开发编译时提示stdsoap2.o中multiple definition of 'namespaces'问题的解决

  我在用自己生成的ONVIF框架开发一个客户端,第一步是想建立一个客户端程序的demo编译通过,结果是按照网上的教程建立的工程,引入的ONVIF框架代码,始终编译不通过。
  问题描述:
  下面是我的工程目录

  

   编译的时候报错:stdsoap2.o multiple definition of `namespaces` 

  问题调查:

  可以看到stdsoap2.c中引入了wsdd.h头文件,就是在这里出现的问题,如果我的main.c中不包含wsdd.h编译没有问题,包含了就跟stdsoap2.c的包含冲突了,就出现问题了。
  问题解决:
  方法1:头文件增加条件编译语句(没用)
  在wsdd.h中增加条件编译语句如下
  #ifndef WSDDNSMAP_H
  #define WSDDNSMAP_H
  。。。
  #endif
  经过确认,此方法对我无效。
  方法2:变量声明放头文件,定义放.c文件(有效)
  此方法参考 https://blog.csdn.net/mantis_1984/article/details/53571758
  新增了一个wsdd.c源码文件,然后将结构体变量定义移过来
  SOAP_NMAC struct Namespace namespaces[] = {
      {"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},
      {"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},
      。。。。。。。。。。。。。
  };
  然后将结构体变量的声明放在头文件,并增加关键字extern
  extern SOAP_NMAC struct Namespace namespaces[];
  问题得到解决
  原理(摘抄原博内容):
  变量的定义和声明的区别。
       声明是向编译器介绍名字--标识符,它告诉编译器“这个函数或变量在某处可找到,它的模样象什么”。而定义是说:“在这里建立变量”或“在这里建立函数”。它为名字分配存储空间。无论定义的是函数还是变量,编译器都要为它们在定义点分配存储空间。对于变量,编译器确定变量的大小,然后在内存中开辟空间来保存其数据,对于函数,编译器会生成代码,这些代码最终也要占用一定的内存。总之就是:把建立空间的声明成为“定义”,把不需要建立存储空间的成为“声明”。
       查看代码,确实我在一个.h文件中定义了一个变量,而这个.h文件被多个文件包含,单独编译都没有问题,但是到链接的时候就出现问题了。
......
struct pdesc const cameractrl_params[] = {
{PT_STRI_, 0,  1, OFFSET(cameractrl, homecmd), "homecmd", 32, 0, NULL, NULL},
    {PT_STRI_, 0,  1, OFFSET(cameractrl, zoomctrl), "zoomctrl", 32, 0, NULL, NULL},
    {PT_STRI_, 0,  1, OFFSET(cameractrl, focusctrl), "focusctrl", 32, 0, NULL, NULL},
    {PT_STRI_, 0,  1, OFFSET(cameractrl, aperturectrl), "aperturectrl", 32, 0, NULL, NULL},
    {PT_NULL_, 0,  0, 0, "", 0, 0, NULL, NULL} /* PT_NULL means tail of struct pdesc array */
};
.....
  一般在.h文件中定义一个变量声明时,在其他文件中只要包含了这个.h文件,编译的时候就会独立被编译器解释,然后每个.C文件会生成独立的标识符和符号表,所以上述代码在单独编译的时候并不会报错,语法是合法的。但是,最后在编译器链接的时候,就会将工程中所有的符号整合在一起,由于文件中有重复的变量,于是就会出现重复定义的错误,系统就是提示你“multiple definition of `xxx`”。
      进一步解释,我们可以这样想象编译每一个C源文件时,相当于一条有管道包围的纵向水流,二者互不干扰。当链接时两条原本相互独立的水管横向流了,所有就出现了重复的元素。所以当进行链接时就会出现重复定义的标示符。重复定义的标示符在这里只是变量,函数不会。因为函数确实只在.c中定义了一次,多次声明是没有问题的,而变量确实出现了两次定义。两次重复的变量定义链接器就不知道该已那个地址作为变量的内存,所以报错。
 
      怎么解决这个问题呢?

      其实只需要将全局变量定义从.h文件中挪到.c文件里,然后在.h文件中用extern做外部声明即可。即在.c文件中声明变量,然后在头文件.h所有的变量声明前加上extern,注意在.h文件中就不要对变量进行初始化赋值了。然后其他需要使用全局变量的.c文件中包含.h文件即可。编译器会为.c生成目标文件,然后链接时,如果该.c文件使用了全局变量,链接器就会链接到此.c文件。其他文件需要使用此全局变量也是同样的方式,目的其实只有一个,就是使变量在内存中唯一化。(我就是看到这然后茅塞顿开的)

原文地址:https://www.cnblogs.com/jieliujas/p/12453992.html