news 2026/10/28 2:02:27

Medelica 之 【类型映射、前缀、数组与Record传参、字符串的内存开辟、注解、modelica:// URI】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Medelica 之 【类型映射、前缀、数组与Record传参、字符串的内存开辟、注解、modelica:// URI】

目录

1.Modelica 基本类型与 C 语言的映射

2. 前缀与类型组合后的行为

3. 数组与 Record 的外部函数传参

3.1 数组传参

3.2 Record 传参

情况 1:Record 只含简单类型成员 → 可整体传

情况 2:Record 含数组成员 → 不能整体传(硬限制)

3.Include 注解:何时需要

4. output String 的内存开辟

4.1 输入 String:const char *

4.2 输出 String:const char ** + ModelicaAllocateString

4.3 完整工作流程

5. annotation

6. 自定义路径:modelica:// URI


1.Modelica 基本类型与 C 语言的映射

Modelica 外部函数调用 C 时,简单类型的默认映射如下:

Modelica 类型C 输入类型C 输出类型(参数传递)
Realdoubledouble *
Integerintint *
Booleanintint *
Stringconst char *const char **(或通过专用分配函数)
Enumerationint(从 1 开始)int *
景C 类型内存管理责任方关键操作
String 作为输入const char *Modelica 环境C 函数只读使用,无需分配/释放内存。
String 作为输出const char **C 函数分配,Modelica 环境释放C 函数必须调用ModelicaAllocateString来为输出字符串分配内存。

2. 前缀与类型组合后的行为

  • input:C 侧按值接收(double、int、const char *)
  • output:C 侧接收指向存储位置的指针(double *、int *),C 函数向该地址写入结果
  • protected 变量:在外部函数调用中与 output 同样传递(即传指针)
  • constant / parameter:在外部函数上下文中,常量通常按 input 方式传入;但更本质的区别在于,parameter 和 constant 在模型方程计数中不计入“未知量”,而 output 类型的变量则参与变量计数
层面决定什么parameter/constant的行为output的行为
类型数据在 C 中的表示(double/int/ ...)doubledouble
前缀(函数调用侧)值传递还是地址传递值传递(同 input)地址传递(指针)
前缀(方程计数侧)是否计入“未知量”不计入(视为已知)计入(视为未知)

3. 数组与 Record 的外部函数传参

3.1 数组传参

要点规则
参数展开一个数组实参 → C 端展开为1 个指针 + 每维 1 个size_t
示例input Real a[3,4]→void foo(double *a, size_t dim1, size_t dim2)
尺寸自动追加Modelica 调用里只写foo(a),尺寸由编译器自动补,不需要手写size(a,1)
内存布局默认row-major(行优先);调 Fortran 77 默认 column-major
布局覆盖需要列优先时加annotation(arrayLayout = "columnMajor")
何时需要改布局C 代码按列优先索引(如从 Fortran 移植)时,否则读错元素
  • row-major vs column-major

二维数组在内存中是一维连续存储的。同一块内存,两种解读方式会导致完全不同的结果

Row-major(行优先)—— C 默认

内存顺序: [0][0], [0][1], [0][2], [0][3], [1][0], [1][1], ... 索引公式: addr(i,j) = a + (i * dim2 + j)

Column-major(列优先)—— Fortran 默认

内存顺序: [0][0], [1][0], [2][0], [0][1], [1][1], ... 索引公式: addr(i,j) = a + (j * dim1 + i)

arrayLayout 注解覆盖默认布局

external "C" foo(a) annotation(arrayLayout = "columnMajor");
场景是否需要arrayLayout
C 代码用a[i*dim2+j](标准 C 风格)不需要,默认rowMajor
C 代码用a[j*dim1+i](Fortran 风格移植)需要设columnMajor
调用 Fortran 77不需要,默认columnMajor

3.2 Record 传参

情况 1:Record 只含简单类型成员 → 可整体传

record Point Real x; Real y; Integer tag; end Point; external "C" r = usePoint_C(p);

C 端映射为同名 struct,成员按声明顺序排列
必须用 Include 提供 struct 定义,否则 C 编译器不认识 Point
头文件放在 Resources/Include/ 下(默认搜索路径),或通过 IncludeDirectory 指定

情况 2:Record 含数组成员 →不能整体传(硬限制)

原因:C struct 大小必须编译期固定,无法容纳动态维度 + size_t 尺寸信息

external "C" foo(traj.t0, traj.x, traj.y);
  • C 端按成员各自类型接收:标量用值,数组用“指针 + size_t”
  • 不需要 struct Trajectory 定义,不需要 Include

3.Include 注解:何时需要

判断标准:生成的 C 代码里有没有 C 编译器不认识的标识符?

需要Include不需要Include
参数含自定义struct(简单 record 整体传)参数全是基本类型(double/int/char*)
C 函数用了<math.h>等标准库但生成代码未包含Record 含数组但拆开传(C 端无 struct 类型名)
C 函数依赖第三方库头文件C 实现自包含、无外部依赖
需要宏定义 /typedef/ 辅助函数原型
  • Include:插入代码内容(#include、#define 等)
  • IncludeDirectory:指定头文件搜索路径(modelica:// 格式)

4. output String 的内存开辟

String 的映射是整个类型体系中最特殊的一个,根源在于内存管理权责

场景C 类型内存管理关键操作
String 输入const char *Modelica 环境只读,无需分配
String 输出const char **C 分配,Modelica 释放必须用ModelicaAllocateString

4.1 输入 String:const char *

void foo(const char *s); // 只读,内存由 Modelica 环境管理

C 函数只读使用,无需操心内存分配或释放

const char *s; // s 可改,*s 不能通过 s 改 const char **s; // s 可改,*s 可改,**s 不能通过 s 改 const char * const *s; // s 可改,*s 不能改,**s 不能通过 s 改

4.2 输出 String:const char ** + ModelicaAllocateString

当 String 作为输出时,C 函数需要把一个新字符串的地址写回 Modelica,因此使用 const char **(指向字符指针的指针)

  • 为什么不能简单 malloc

malloc 分配的内存所有权仍留在外部 C 代码,Modelica 仿真环境既不知道也不负责用 free 释放它,因此会造成内存泄漏;同时这块内存游离于仿真环境私有的栈/垃圾回收等内存管理机制之外,环境无法追踪、回收或安全清理,尤其在 DLL 卸载等场景下还可能因运行时/GC 销毁而变成无效指针导致崩溃,所以规范强制要求:返回非字面量字符串时,必须使用专用分配函数:由环境在合适时机安全释放

const char* ModelicaAllocateString(size_t len); // 分配 len 字节

4.3 完整工作流程

// C 函数内部 void getMessage(const char **out_str) { const char *msg = "Hello from C"; size_t len = strlen(msg); // 步骤 1:必须用 ModelicaAllocateString 分配内存 char *buf = (char*)ModelicaAllocateString(len); // 步骤 2:拷贝内容 strcpy(buf, msg); // 步骤 3:把地址写回输出参数 *out_str = buf; }
  1. C 函数调用 ModelicaAllocateString 申请内存
  2. 写入字符串内容
  3. 通过 const char ** 把地址写回 Modelica
  4. 外部函数返回后,Modelica 环境接管内存的释放

5. annotation

注解(annotation)是 Modelica 中用于存储模型附加元信息的机制。它不参与方程求解,但会指导工具链完成图形渲染、文档生成、外部资源定位、仿真设置、代码生成等任务

注解的语法与类修改(class modification)相同,使用圆括号(...),可以出现在类、组件、方程、函数等多个位置

class MyModel Real x; equation der(x) = -x; annotation ( Documentation( info = "这是一个一阶指数衰减模型", revisions = "v1.0 - 初始版本" ), Icon( coordinateSystem(extent = {{-100, -100}, {100, 100}}), graphics = { Rectangle(extent = {{-80, -50}, {80, 50}}, borderColor = {30, 91, 255}, fillColor = {219, 234, 254}) } ), uses(Modelica(version = "3.2.3")) ); end MyModel;

一个类可以拥有多个注解,注解之间用逗号分隔。注解的值可以是字符串、数字、布尔值、数组、记录构造,甚至嵌套的注解调用

  • 常见注解类型一览

注解位置说明
Documentation类 / 组件info描述、revisions版本历史、figures仿真图
Icon类模型图标(面板内显示的图形)
Diagram类模型框图(内部组件连接图)
Connectorconnector连接器图标和图形设置
SmoothOrderfunction函数的可微分阶数
derivativefunction指定导函数名称
Inversefunction指定逆函数
Includefunction / class外部函数声明所需的头文件内容注入
IncludeDirectoryfunction / class头文件搜索路径
Libraryfunction / class链接库名称
LibraryDirectoryfunction / class编译好的库文件搜索路径
arrayLayoutfunction / class数组内存布局(rowMajor/columnMajor)
uses(Modelica(...))package / class声明所使用的标准库版本
version/date/lastModifiedclass版本号与时间戳
Dialogparameter / component参数对话框的group、tab分组
defaultComponentNameclass图形化拖放时默认组件名前缀
PreferredViewclass首选视图(icon/diagram/text)

如果不写 IncludeDirectory、LibraryDirectory,工具会在默认位置查找 Include 中引用的头文件:包含该外部函数的包(package.mo)所在目录下的 Resources/Include 子文件夹

6. 自定义路径:modelica:// URI

modelica:// 是一个逻辑 URI,它的含义是:“相对于某个 Modelica 库的根目录”。当工具(如 OpenModelica、Dymola)解析这个 URI 时,会自动将其转换为当前机器上的绝对文件路径

示例:假设你的库在包(MyPackage,包名)的 CustomLibs 文件夹下

annotation( Library = "MyAddDll", // 库名,不带前缀和后缀 LibraryDirectory = "modelica://MyPackage/CustomLibs" );
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 2:02:18

小白程序员必看:收藏这份大模型“炼成“流水线指南,从预训练到后训练一篇读懂!

本文详细解析了大模型的五个核心训练阶段&#xff1a;数据准备、预训练、指令微调、对齐与后训练&#xff0c;帮助读者理解从基础模型到高级应用的完整流程。通过分析 REA、RSI 智能体与 Jev 判别小模型等热点案例&#xff0c;揭示每个阶段的关键技术和实际应用。对于想要入门或…

作者头像 李华
网站建设 2026/10/28 2:01:46

我国高精度地基授时系统正式进入试运行

当我们刷手机、转账交易、电网调度、5G基站通信时&#xff0c;背后都离不开一套看不见的“时间基准”。长久以来&#xff0c;卫星是大家最熟悉的授时来源&#xff0c;但卫星信号容易受到干扰、欺骗&#xff0c;一旦信号异常&#xff0c;金融、电力、通信等关键行业就会面临风险…

作者头像 李华
网站建设 2026/10/28 2:01:38

STM32CubeMX配置串口通信(F407ZGT6)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 2:01:28

ollama v0.40.11发布:macOS原生语音生成上线,d3决策模型正式加入

2026年10月26日&#xff0c;Ollama 发布 v0.40.11 版本。本次更新围绕两个核心方向展开&#xff1a;一是面向 macOS 的语音生成能力&#xff0c;二是引入 d3 决策模型。 对于希望让文本、聊天回复直接以语音形式输出的使用者来说&#xff0c;v0.40.11 带来了新的语音生成方式&a…

作者头像 李华
网站建设 2026/10/28 2:01:27

从零到一认识外骨骼(2)

接前一篇文章&#xff1a;从零到一认识外骨骼&#xff08;1&#xff09; 本文内容参考&#xff1a; 知识宝典丨解码科技&#xff1a;外骨骼机器人的前世今生 从《明日边缘》走向现实世界 军用动力外骨骼编年史 _ 游民星空 GamerSky.com 外骨骼机器人&#xff08;一&#xff…

作者头像 李华