【问题标题】:sprintf giving undefined resultssprintf 给出未定义的结果
【发布时间】:2015-07-09 02:22:30
【问题描述】:

我刚刚完成了一个用 C 语言编写的小 dll。它是第 3 方软件和占星术 dll 之间的接口。基本上,它会根据出生日期、时间、经度和纬度,获得沿黄道的占星宫位置经度。因为第 3 方软件需要返回字符串,所以我将房屋经度转换为 ascii,并使用 sprintf 将它们与逗号串在一起。 如果我在函数“housecusps”中声明返回字符串“retrnString”,我的变量就会损坏(主要是“indx”)。然而,一旦“retrnString”被声明为全局,它就可以完美地工作。谁能解释一下原因???

#include <stdio.h>
#include <windows.h>
#include "swephexp.h"
#include "Wave59_SDK.h"

typedef  int32 (*JULDAYPTR)(int32, int32, int32, int32, int32, double, int32, double*, char*);
typedef int (*HOUSECUSPSPTR)(double, double, double, int, double*, double*);
char retrnString[96];

BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                       DWORD reason        /* Reason this function is being called. */ ,
                       LPVOID reserved     /* Not used. */ );

char* __declspec(dllexport) housecusps(WAVE59_DATASTRUCT *price_ptr, int currentptr,
            int *int_args,int num_int_args,double *double_args,
            int num_double_args,char **string_args,int num_string_args)
{
    int32 iyear = int_args[0];
    int32 imnth = int_args[1];  
    int32 iday = int_args[2];
    int32 ihr = int_args[3];
    int32 imin = int_args[4];  
    int32 gregflag = SE_GREG_CAL;
    double dret[2], cuspArray[13], ascmc[10], julianDays;
    char serr[256];
    const double zeroSecs = 0;
    int hsys = 'P';
    int ctr, indx;
    JULDAYPTR JulDay;
    HOUSECUSPSPTR HouseCusps;

    HINSTANCE astrologyDLL = LoadLibrary("c:\\sweph\\bin\\swetrs32.dll");
    if (astrologyDLL == NULL)
       return "Error loading swedll32.dll";
    JulDay = (JULDAYPTR)GetProcAddress(astrologyDLL, "_swe_utc_to_jd@40");
    if (JulDay == NULL)
       return "Error loading swe_utc_to_jd";
    if (JulDay(iyear,imnth,iday,ihr,imin,zeroSecs,gregflag,dret,serr) == ERR)
       return serr;
    julianDays = dret[1];
    HouseCusps = (HOUSECUSPSPTR)GetProcAddress(astrologyDLL, "_swe_houses@36");
    if (HouseCusps == NULL)
       return "Error loading swe_houses";
    /*//Parms:- dret[1] = Julian day in UT, double_args[0] = Latitude, double_args[1] = Longitude.*/
    if (HouseCusps(julianDays,double_args[0],double_args[1],hsys,cuspArray,ascmc) == ERR)
        return "Error in swe_houses"; 
    indx = 0;
    for (ctr = 1;ctr < 13; ctr++)
    {
        indx += sprintf(retrnString + indx,"%.3f",cuspArray[ctr]);
        if (ctr != 12)
           indx += sprintf(retrnString + indx ,"%c",',');
    }
    FreeLibrary(astrologyDLL);
    return retrnString;
}

【问题讨论】:

  • 请注意,if (JulDay(iyear,imnth,iday,ihr,imin,zeroSecs,gregflag,dret,serr) == ERR) return serr; 正在返回一个指向局部变量的指针。这是不好的。它与您在将其设为全球之前对 retrnString 所做的操作基本相同。
  • @Jonathan Leffler 否 - 它返回 int。
  • 我指的是代码中的return serr;,而不是JulDay 函数返回的内容。

标签: c printf


【解决方案1】:

如果你把char retrnString[96];放在funchousecusps(...)中,它是一个留在堆栈中的局部变量,当你从那个函数返回时,这个堆栈空间将被清除,这就是它被破坏的原因。

还有一些方法可以从函数中“返回/获取”此类内容,

  1. 一个全局变量char retrnString[96];,就像你所做的那样。

  2. malloc一个内存来保存内容并返回它,以后记得free

通知
更好的选择是让函数接受输出缓冲区作为参数。否则,如果调用者使用不同的分配器或不同的内存池,这里的第二个选项(malloc internal )可能会出现问题。 ----@Matt McNabb 的建议

使用全局变量作为返回值的主要缺点是您的代码变得不可重入。您不能有两个线程同时调用该函数。此外,在调用该函数一次之后,您必须在第二次调用该函数之前完成第一个值,或者在进行第二次调用之前复制第一次调用中的字符串。 ----@Jonathan Leffler 的评论

【讨论】:

  • 更好的选择是让函数接受输出缓冲区作为参数。如果调用者使用不同的分配器或不同的内存池,您的选项 (2) 会出现问题
  • 使用全局变量作为返回值的主要缺点是您的代码变得不可重入。您不能有两个线程同时调用该函数。此外,在调用该函数一次后,您必须在第二次调用该函数之前完成第一个值,或者在进行第二次调用之前复制第一次调用中的字符串。
  • 确实如此。谢谢。要编写可重入代码,请尽量避免使用全局变量。如果必须使用它,则可能需要互斥锁。所以,答案应该再次细化:)
  • 对不起误导了大家。问题不是从函数 housecusps 返回后出现,而是在 sprintf 后出现。到 housecusps 即将返回时,我的变量已经损坏了。
猜你喜欢
  • 2013-12-23
  • 2021-05-20
  • 1970-01-01
  • 2017-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2016-01-31
相关资源
最近更新 更多