0

我一直在使用 C 语言在 Scilab/Xcos(Matlab/Simulink 的开源变体)中开发一个块。为此,Scilab/Xcos 提供了一个称为 CBLOCK4 的特殊模块。一旦我将此块放入模拟中,就会自动生成一个 C 语言存根。该存根的一部分是实现块行为的函数的模板。此函数在其参数中接受指向scicos_block结构的指针:

typedef struct {
  int nevprt;
  voidg funpt ;
  int type;
  int scsptr;
  int nz;
  double *z;
  int noz;
  int *ozsz;
  int *oztyp;
  void **ozptr;
  int nx;
  double *x;
  double *xd;
  double *res;
  int nin;
  int *insz;
  void **inptr;
  int nout;
  int *outsz;
  void **outptr;
  int nevout;
  double *evout;
  int nrpar;
  double *rpar;
  int nipar;
  int *ipar;
  int nopar;
  int *oparsz;
  int *opartyp;
  void **oparptr;
  int ng;
  double *g;
  int ztyp;
  int *jroot;
  char *label;
  void **work;
  int nmode;
  int *mode;
} scicos_block;

该项目work可能旨在用于存储存储块的内部状态变量的另一个地址的存储地址。我试图用work项目用法来实现 Scilab/Xcos 块:

#include "scicos_block4.h"

#define U  ((double *)GetRealInPortPtrs(block, 1))
#define Y  ((double *)GetRealOutPortPtrs(block, 1))

// parameters
#define Tu (GetRparPtrs(block)[0])
#define Td (GetRparPtrs(block)[1])
#define T  (GetRparPtrs(block)[2])


void Ramp(scicos_block *block, int flag)
{
 
  double *target;
  double *inputDelta;
  double *out;

  if(flag == 4) 
  {
    /* init */
    if((*(block->work) = (double *)scicos_malloc(sizeof(double)*3)) == NULL)
    {
        set_block_error(-16);
        return;
    }
        
    target      = (double*)(*(block->work));
    inputDelta  = (double*)(*(block->work + 1));
    out         = (double*)(*(block->work + 2));

    *target     = 0;
    *inputDelta = 0;
    *out        = 0; 

  }
  else if(flag == 1) 
  {
    /* output computation */ 
    if(U[0] != *target)
    {
        *target = U[0];
        
        if(*target - Y[0] < 0)
        {
            *inputDelta = Y[0] - *target;
        }
        else
        {
            *inputDelta = *target - Y[0];
        }
    }
    
    if(*target > Y[0])
    {
        *out += *inputDelta*T/Tu;
        if(*out > *target)
        {
            *out = *target;
        }
    }
    else if(*target < Y[0])
    {
        *out -= *inputDelta*T/Td;
        if(*out < *target)
        {
            *out = *target;
        }
    }
    
    Y[0] = *out;  
  } 
  else  if (flag == 5) 
  {
    /* ending */
    scicos_free(*(block->work));

  }

}

我能够成功编译包含此代码的块,但如果我开始模拟它会崩溃。我对内存的动态分配以及我使用它的方式有疑问。

请任何人看看我的代码(即带有标志 == 4 的 if 正文中的部分)并告诉我我做错了什么?

4

2 回答 2

1

This line

target      = (double*)(*(block->work));

is correct but these lines

inputDelta  = (double*)(*(block->work + 1));
out         = (double*)(*(block->work + 2));

are wrong.

(*(block->work) will give you the pointer to the first of the three malloc'ed doubles.

However, you don't get the next double like you did - you are adding one too early. Change it like:

(double*)(*(block->work + 1));   // Wrong !!
(double*)(*(block->work)) + 1;   // Correct !!
^^^^^^^^^^^^^^^^^^^^^^^^^   ^
Get pointer to malloced     Then add 1 to get to the second malloc'ed double
memory (i.e. the first
malloc'ed double) and use 
it as a double-pointer

Or simply do it like:

target      = (double*)(*(block->work));
inputDelta  = target + 1;
out         = target + 2;

BTW: You don't need all the casting. Just remove it.

Edit: In a comment OP tells that it still crashes

The posted code doesn't tell us whether block->work has been initialized before calling Ramp. If it hasn't been initialized before then doing *(block->work) will be illegal - and may cause a crash.

So maybe the code is missing something like:

/* init */
block->work = malloc(sizeof *block->work);  // Add this line
if((*(block->work) = (double *)scicos_malloc(sizeof(double)*3)) == NULL)
于 2020-09-28T13:04:35.153 回答
0

正如用户4386427回答中提到的,(double*)(*(block->work + 1))应该是(double*)(*(block->work)) + 1。如果sizeof(double)并且sizeof(void*)具有不同的值,这一点尤其重要。(在典型的 64 位系统上,它们具有相同的值,但在典型的 32 位系统上,它们具有不同的值。)

另一个严重的问题是 when 、 和flag == 1变量target包含未初始化的值但被取消引用。变量需要在块中分配,然后才能以与块中相同的方式取消引用。inputDeltaoutelse if (flag == 1)if (flag == 4)

struct如果定义了一个类型来保存工作数据,我认为代码会更干净:

struct Ramp_work
{
    double target;
    double inputDelta;
    double out;
};

void Ramp(scicos_block *block, int flag)
{
    struct Ramp_work *work;

    if (flag == 4)
    {
        /* init */
        work = scicos_malloc(sizeof(*work));
        *block->work = work;
        if (work == NULL)
        {
            set_block_error(-16);
            return;
        }
        work->target = 0;
        work->inputDelta = 0;
        work->out = 0;
    }
    else if (flag == 1)
    {
        /* output computation */
        work = *block->work;
        if (U[0] != work->target)
        {
             /* etc. */
        }
        /* etc. */
    }
    else if (flag == 5)
    {
        /* ending */
        scicos_free(*block->work);
    }
}
于 2020-09-28T15:42:34.300 回答