最近在利用VS 2017 调用Netcdf的c语言代码处理CERES数据集时,在安装完cdf软件时,需要用VS2017调用系统文件下的include\bin\lib的文件时,碰到了一些动态库的问题,花了挺久时间才整好,今天分享给大家:
1.动态库的创建
1)首先利用VS2017 建立两个空项目,第一个为test项目,第二个为动态库项目;此处需要将项目的属性分别设置为.exe 和.dll;
2)在动态库项目——Danamic_ex中建立.h 和.c 文件;在.h中编写如下相应代码:
#ifndef _DANAMIC_DLL_H
#define _DANAMIC_DLL_H
#ifdef _DLL_API
#define DANAMIC_DLL_API __declspec(dllexport)
#else
#define DANAMIC_DLL_API __declspec(dllimport)
#endif // _DLL_API
#ifdef __cplusplus
extern "C" {
#endif // _cplusplus
DANAMIC_DLL_API int Add_z(int a, int b);
DANAMIC_DLL_API int Sub_z(int a, int b);
DANAMIC_DLL_API void print_z(void);
#ifdef __cplusplus
}
#endif // _cplusplus
#ifndef _DANAMIC_DLL_H
#define _DANAMIC_DLL_H
代码段
#endif // !_DANAMIC_DLL_H
---上述代码目的:为了避免重复定义而添加一个预定义:
#ifdef _DLL_API
#define DANAMIC_DLL_API __declspec(dllexport)
#else
#define DANAMIC_DLL_API __declspec(dllimport)
#endif // _DLL_API
//----VS中自己的一个预定义,避免在生成文件中和调用文件中出现dllexport和dllimport的不同
//另外需要注意的一个问题就是,__declspec(dllexport)的前边应该是两个下划线
#ifdef __cplusplus
extern "C" {
#endif // _cplusplus
代码。。。。
#ifdef __cplusplus
}
#endif // _cplusplus
//这段代码是为了适应c/c++的编译环境,__cplusplus在c++编译器中定义为非零值;当使用c编译器编译时,__cplusplus的值为0值,不需要编译,直接运行代码;当使用c++编译时,__cplusplus的值为非零值,所以extern “C”{}存在,强制要求c++编译器按照c语言的风格编译;
在Danamic_dll.c中为了测试方便,编写如下代码:
#include "Danamic_dll.h"
#include<stdio.h>
DANAMIC_DLL_API int Add_z(int a, int b)
{
return a+b;
}
DANAMIC_DLL_API int Sub_z(int a, int b)
{
return a-b;
}
DANAMIC_DLL_API void print_z(void)
{
printf("\nOK!\n");
}
3)生成建立动态连链接库,会生成.dll、.lib、.pdb等文件,如下图其中的.dll和.lib为我们所需要的文件;这里的.lib 文件不同于静态库中的.lib文件,其中不包含函数的代码,只是包含一些辅助信息,建立其.dll 和.h的联系;
动态库的生成也可以使用.def 文件来设置,这种方式可以保证生成动态库中函数入口的名称不变;
2.动态库的使用
为了验证动态库的使用,以及后边Netcdf的配置方便,这里给出使用方法:
1)第一种使用方法,与调用静态库一样,见本人的另一篇文章,这里给出头文件的写法,其主要是通过路径来调用,但是要注意一定要保持.dll文件和.exe 保持在同一个文件夹下才可以;
2)使用项目的属性设置来配置,将.lib、.h的路径包含在其中:其设置如下:
c/c++头文件.h添加:
c/c++的.lib添加:
上述设置完成后,也一定要保持.dll文件和.exe 保持在同一个文件夹下才可以,这个行为可以通过自己手动复制粘贴,或更改动态库生成的保存文件;
由于本文档是为了说明动态库的使用,以便后边在VS2017 中调用netcdf 中的使用,因此对于动态库的入口函数DLLmain没有整理,以及动态的动态加载和释放没有整理;
2、VS 2017 +Netcdf环境配置
Netcdf可以在NetCDF: The NetCDF-C Tutorial中下载,netcdf:netCDF Downloads (官方地址)
在c盘中安装后,如下图
其中bin中为.dll文件,include中为.h文件,lib中为.lib文件;
新建一个空文件:
环境配置
项目属性\VC++目录\包含目录 添加 C:\Program Files (x86)\netCDF 4.6.1\include (安装位置的include目录)
项目属性\VC++目录\库目录 添加 C:\Program Files (x86)\netCDF 4.6.1\lib (安装位置的lib目录)
项目属性\链接器\输入\附加依赖项 添加 netcdf.lib
测试代码如下:
#include <stdlib.h>
#include <stdio.h>
#include <netcdf.h>
/* This is the name of the data file we will create. */
#define FILE_NAME "simple_xy.nc"
/* We are writing 2D data, a 6 x 12 grid. */
#define NDIMS 2
#define NX 6
#define NY 12
/* Handle errors by printing an error message and exiting with a
* non-zero status. */
#define ERRCODE 2
#define ERR(e) {printf("Error: %s\n", nc_strerror(e)); exit(ERRCODE);}
int
main()
{
/* When we create netCDF variables and dimensions, we get back an
* ID for each one. */
int ncid, x_dimid, y_dimid, varid;
int dimids[NDIMS];
/* This is the data array we will write. It will be filled with a
* progression of numbers for this example. */
int data_out[NX][NY];
/* Loop indexes, and error handling. */
int x, y, retval;
/* Create some pretend data. If this wasn't an example program, we
* would have some real data to write, for example, model
* output. */
for (x = 0; x < NX; x++)
for (y = 0; y < NY; y++)
data_out[x][y] = x * NY + y;
/* Always check the return code of every netCDF function call. In
* this example program, any retval which is not equal to NC_NOERR
* (0) will cause the program to print an error message and exit
* with a non-zero return code. */
/* Create the file. The NC_CLOBBER parameter tells netCDF to
* overwrite this file, if it already exists.*/
if ((retval = nc_create(FILE_NAME, NC_CLOBBER, &ncid)))
ERR(retval);
/* Define the dimensions. NetCDF will hand back an ID for each. */
if ((retval = nc_def_dim(ncid, "x", NX, &x_dimid)))
ERR(retval);
if ((retval = nc_def_dim(ncid, "y", NY, &y_dimid)))
ERR(retval);
/* The dimids array is used to pass the IDs of the dimensions of
* the variable. */
dimids[0] = x_dimid;
dimids[1] = y_dimid;
/* Define the variable. The type of the variable in this case is
* NC_INT (4-byte integer). */
if ((retval = nc_def_var(ncid, "data", NC_INT, NDIMS,
dimids, &varid)))
ERR(retval);
/* End define mode. This tells netCDF we are done defining
* metadata. */
if ((retval = nc_enddef(ncid)))
ERR(retval);
/* Write the pretend data to the file. Although netCDF supports
* reading and writing subsets of data, in this case we write all
* the data in one operation. */
if ((retval = nc_put_var_int(ncid, varid, &data_out[0][0])))
ERR(retval);
/* Close the file. This frees up any internal netCDF resources
* associated with the file, and flushes any buffers. */
if ((retval = nc_close(ncid)))
ERR(retval);
printf("*** SUCCESS writing example file simple_xy.nc!\n");
system("pause");
return 0;
}
运行结果:
大功告成,一切顺利!
以上供大家学习!