我需要创建一个DLL文件,该文件可用于MS Access和其他应用程序,这些应用程序将在输入参数时返回字符串。我对MS Access非常熟悉,但对C来说是一个绝对的新手。
以下是我正在尝试的代码。我希望能够发出类似getstring(32.1, 123.2, "here", 25)
的调用,并让它返回长度最多为60个字符的字符串。实际代码工作正常,buf
包含我想要完成后运行的字符串,但我无法将其交回调用函数。
更新: 好的,我已经研究了如何创建DLL并从VBA运行一个函数,但我仍然在努力理解如何返回字符串。我想如果我能让这个工作,我可以解决我的整个项目。通过运行以下代码,我可以让VBA返回输入数字的平方,例如给它一个10的参数,我得到100的答案
double _stdcall square(double *x)
{
return *x * *x;
}
然而,当我在Excel中运行以下代码并为其提供参数" test"我得到的只是一个方形盒子。
char _stdcall Boxx(char *x)
{
return *x;
}
在这种情况下,我想要它返回的就是我输入的内容。如果我可以让它返回,我希望能够用实际结果替换它。有什么建议吗?
char * Getstring(double lat, double lon, char *name, double zoom)
{
char buf[60] = { '\0' }; // Set the max length of the final link string
int ret = GenShortDroidMapUrl(lat, lon, zoom, name, buf, sizeof(buf) - 1);
return buf;
}
答案 0 :(得分:2)
在发布的代码中,buf[]
是一个自动变量,其生命周期在Getstring()
函数返回后结束。由于当程序的控制权返回给调用者时,buf[]
将不再存在,因此在Getstring()
返回后,指向此变量的指针将无效。
一种解决方案是将另一个参数传递给Getstring()
函数以接受字符串以及size参数。由于buf
将衰减到函数调用中的指针,sizeof
运算符无法在Getstring()
中用于查找数组的大小,但buf_sz
保留此值:
char * Getstring(char *buf, size_t buf_sz, double lat, double lon, char *name, double zoom)
{
// buf[] has been zero-initialized in the caller
int ret = GenShortDroidMapUrl(lat, lon, zoom, name, buf, buf_sz - 1);
return buf;
}
另一个不需要更改函数签名的选项是为返回的字符串动态分配存储空间。同样,buf
是指向char
中Getstring()
的指针,因此需要替换sizeof
中的GenShortDroidMapUrl()
表达式;这次使用常量BUF_SZ
。请注意,调用者稍后需要malloc
ed内存free
。
#include <string.h>
#define BUF_SZ 60
/* ... */
char * Getstring(double lat, double lon, char *name, double zoom)
{
char *buf = malloc(sizeof *buf * BUF_SZ);
memset(buf, '\0', BUF_SZ);
/* Or use calloc() and avoid the call to memset() */
// char *buf = calloc(BUF_SZ, sizeof *buf);
int ret = GenShortDroidMapUrl(lat, lon, zoom, name, buf, BUF_SZ - 1);
return buf;
}
如果Getstring()
是库的一部分,则需要确保deallocator函数与分配函数匹配。也就是说,如果链接malloc()
的{{1}}或calloc()
版本与调用代码链接的Getstring()
版本不同,则可能会出现问题。一种解决方案是提供与库的解除分配功能。这可以像在调用者使用的另一个函数中包装free()
一样简单,以确保使用匹配的解除分配器。这里,函数free()
是DLL的一部分,DLL_Free()
,malloc()
和calloc()
在创建DLL时都会链接到同一个库。使用free()
的调用方将使用Getstring()
取消分配。从调用者,DLL_Free()
可能无法正常工作以释放由free()
分配的内存,但Getstring()
会因为此解除分配器使用与所使用的分配器匹配的DLL_Free()
版本在DLL中。
free()
答案 1 :(得分:1)
有许多方法可以返回字符串,但要尊重缓冲区的生命周期:
Can a local variable's memory be accessed outside its scope?
一个是让呼叫者提供缓冲区。返回需要多少空间,简单的比较会告诉您它是否足够。
另一种方法是使用静态的,可选的线程局部缓冲区。注意对并发性和重入性的限制。
最后,您可以动态分配它。请记住,它必须使用相同的系统释放,在Windows上通常意味着您必须手动导出从DLL中释放它的方式。最好不要重新发明轮子,look at BSTR
s for example。
答案 2 :(得分:0)
您可以声明buf static
并让函数返回const char *
。但那不是reentrant。所以另一个解决方案是返回strdup(buf)
,它将在使用后返回调用者需要free
的副本(否则你将有内存泄漏)。