问题描述
我一直在使用C语言在Scilab / Xcos(Matlab / Simulink的开源变体)中开发一个模块。为此,Scilab / Xcos提供了一个称为CBLOCK4的特殊块。一旦将此块放入仿真中,就会自动生成一个C语言存根。该存根的一部分是用于实现该块行为的功能的模板。此函数在其参数中接受指向@H_502_1@scicos_block结构的指针:
@H_502_1@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;
项目@H_502_1@work可能旨在用于存储另一个地址的地址,在另一个地址存储的是块的内部状态变量。我尝试使用@H_502_1@work项目用法来实现Scilab / Xcos块:
@H_502_1@#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)); } }
我能够成功地编译包含此代码的块,但是如果我开始仿真,它将崩溃。我对内存的动态分配及其使用方式有疑问。
请任何人看看我的代码(即if主体中带有flag == 4的部分),然后告诉我我在做什么错吗?
解决方法
此行
target = (double*)(*(block->work));
是正确的,但这些行
inputDelta = (double*)(*(block->work + 1));
out = (double*)(*(block->work + 2));
错了。
(*(block->work)
将为您提供三个malloc的双打中的第一个的指针。
但是,您不会像以前那样获得下一个加倍-您添加得太早了。像这样更改它:
(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
或者只是这样做:
target = (double*)(*(block->work));
inputDelta = target + 1;
out = target + 2;
顺便说一句:您不需要所有的转换。只需将其删除。
编辑:在评论中,OP告知它仍然崩溃
发布的代码未告诉我们block->work
在调用Ramp
之前是否已初始化。如果尚未进行过初始化,则进行*(block->work)
是非法的-可能会导致崩溃。
所以也许代码缺少诸如以下内容:
/* init */
block->work = malloc(sizeof *block->work); // Add this line
if((*(block->work) = (double *)scicos_malloc(sizeof(double)*3)) == NULL)
,
如用户4386427的answer中所述,(double*)(*(block->work + 1))
应该为(double*)(*(block->work)) + 1
。如果sizeof(double)
和sizeof(void*)
具有不同的值,这尤其重要。 (在典型的64位系统上,它们将具有相同的值,但是在典型的32位系统上,它们将具有不同的值。)
另一个严重的问题是,当flag == 1
,target
,inputDelta
和out
变量包含未初始化的值但被取消引用时。必须先在else 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);
}
}