核心思想
要理解C语言和LabVIEW的本质:

(图片来源网络,侵删)
- C语言:是编译型语言,编译后生成一个可执行文件(
.exe)或动态链接库(.dll/.so),它运行在操作系统层面,直接与硬件交互。 - LabVIEW:是图形化编程语言,其代码最终也会被编译成可执行文件(
.exe)或共享库(.dll),它运行在操作系统之上,并拥有自己的图形用户界面。
C语言调用LabVIEW,本质上是一个进程(C程序)与另一个进程(LabVIEW程序或LabVIEW生成的DLL)进行通信。
调用LabVIEW生成的共享库(.dll / .so)【推荐,性能最高】
这是最常用、性能最好的方法,它将LabVIEW的功能封装成一个标准的动态链接库,然后像调用普通Windows API或第三方库一样,在C程序中调用它。
工作原理:
- 在LabVIEW中,将VI(虚拟仪器,即LabVIEW的程序)配置为“共享库”或“NI-compiled Library”。
- LabVIEW编译器会生成一个
.dll文件(Windows)或.so文件(Linux),以及一个头文件(.h)和一个用于说明输入输出参数类型的文件(.lvlib或.cat)。 - 在C语言项目中,包含生成的头文件,链接生成的
.dll库文件,然后直接调用其中的函数。
详细步骤
在LabVIEW中创建并导出共享库

(图片来源网络,侵删)
假设我们有一个简单的LabVIEW VI,它接收一个数字,进行平方运算后返回结果。
-
LabVIEW VI设计:
- 前面板:一个数值输入控件(命名为
inputNumber),一个数值显示控件(命名为outputResult)。 - 程序框图:将
inputNumber连接到一个乘法函数的输入端,两个输入端都连接同一个,然后将结果连接到outputResult。
- 前面板:一个数值输入控件(命名为
-
配置为共享库:
- 在LabVIEW中,打开你的VI。
- 点击 文件 -> 导出 -> 共享库。
- 在弹出的对话框中:
- 库名称:给你的库起一个名字,
MyCalculator。 - 目标目录:选择一个保存位置。
- VI 设置:确保你的VI被勾选,可以将其设置为“主VI”。
- 函数面板:点击“添加”,选择你的VI,LabVIEW会自动将VI的输入控件和输出显示控件作为C函数的参数。
- 数据类型映射:LabVIEW会自动将数据类型(如
I32)映射到C语言的数据类型(如int32_t),通常保持默认即可。
- 库名称:给你的库起一个名字,
- 点击 确定,LabVIEW会开始编译,完成后,你会在目标目录下看到:
MyCalculator.dll(Windows) 或libMyCalculator.so(Linux)MyCalculator.h(C语言头文件)MyCalculator.lib(Windows库文件,用于链接)MyCalculator.lvlib(LabVIEW库文件,用于高级应用)
在C语言中调用生成的DLL

(图片来源网络,侵删)
我们写一个C程序来调用 MyCalculator.dll 中的 Square 函数。
- C语言代码 (
main.c)
#include <stdio.h>
#include <windows.h> // Windows下需要此头文件来加载DLL
// #include <dlfcn.h> // Linux下需要此头文件来加载.so文件
// 包含LabVIEW生成的头文件
#include "MyCalculator.h" // <-- 确保路径正确
// 定义函数指针类型,用于接收从DLL中加载的函数
// 函数签名必须与.h文件中声明的一致
typedef int32_t (*SquareFunc)(int32_t input);
int main() {
// 1. 加载LabVIEW生成的DLL文件
HINSTANCE hDLL = LoadLibrary(TEXT("MyCalculator.dll")); // Windows
// void* hDLL = dlopen("./libMyCalculator.so", RTLD_LAZY); // Linux
if (hDLL == NULL) { // if (!hDLL) for Linux
printf("无法加载 DLL/so 文件,请确保文件在当前目录或系统PATH中,\n");
return 1;
}
// 2. 从DLL中获取函数地址
SquareFunc pSquare = (SquareFunc)GetProcAddress(hDLL, "Square"); // Windows
// SquareFunc pSquare = (SquareFunc)dlsym(hDLL, "Square"); // Linux
if (pSquare == NULL) { // if (dlerror() != NULL) for Linux
printf("无法找到 'Square' 函数,\n");
FreeLibrary(hDLL); // Windows
// dlclose(hDLL); // Linux
return 1;
}
// 3. 调用函数
int32_t inputValue = 5;
int32_t result = pSquare(inputValue);
printf("C程序调用LabVIEW函数:\n");
printf("输入: %d\n", inputValue);
printf("LabVIEW计算结果: %d\n", result);
// 4. 释放DLL
FreeLibrary(hDLL); // Windows
// dlclose(hDLL); // Linux
return 0;
}
- 编译和运行 (Windows)
- 将
main.c、MyCalculator.h和MyCalculator.lib放在同一目录下。 - 使用Visual Studio的开发人员命令提示符,运行以下命令:
cl main.c MyCalculator.lib user32.lib
cl是微软的C/C++编译器。MyCalculator.lib是我们需要链接的导入库。user32.lib是LoadLibrary和GetProcAddress函数所在的库。
- 运行生成的
main.exe,你应该能看到正确的结果。
- 将
通过命令行调用【最简单,但性能较低】
这种方法不涉及复杂的DLL接口,而是将LabVIEW VI当作一个独立的可执行程序来运行,C程序通过启动这个进程,并向它传递命令行参数,然后从其标准输出中读取结果。
工作原理:
- 在LabVIEW VI中,使用“命令行输入”函数获取参数,并将结果通过“命令行输出”函数打印到控制台。
- C程序使用
system()(Windows) 或popen()(跨平台) 函数来执行LabVIEW生成的.exe文件,并传递参数。 - C程序捕获
.exe程序的输出,解析后得到结果。
详细步骤
在LabVIEW中配置VI以接受命令行参数
-
LabVIEW VI设计:
- 在程序框图中,找到 函数 -> 编程 -> 应用程序控制 -> 命令行输入 函数。
- 将它拖入框图,它会返回一个字符串数组,包含所有命令行参数。
- 取第一个参数(索引为0,通常是程序名),第二个参数(索引为1)才是我们传入的数值。
- 将字符串转换为数值(使用 字符串/数值转换 -> 十进制字符串转换为数值 函数)。
- 进行平方运算。
- 将结果转换为字符串(使用 数值/字符串转换 -> 数值转换为十进制字符串 函数)。
- 使用 函数 -> 编程 -> 字符串 -> 格式化写入 函数,将结果格式化为 "Result: [数值]"。
- 使用 函数 -> 编程 -> I/O -> 写入标准输出 函数将结果打印到控制台。
-
生成独立可执行文件:
- 在LabVIEW中,点击 文件 -> 构建 -> 应用程序。
- 选择目标目录,配置应用程序信息,然后点击 构建。
- LabVIEW会生成一个
.exe文件,MyCalculator.exe。
在C语言中调用生成的EXE
- C语言代码 (
main_cli.c)
#include <stdio.h>
#include <stdlib.h> // 用于 system() 和 popen()
// 使用 popen() 的方法(推荐,可以获取输出)
int main() {
char command[100];
char result_buffer[128];
// 1. 构建要执行的命令
// 注意:如果你的.exe有空格,需要用引号括起来,如 "\"C:\My Path\MyCalculator.exe\""
int inputValue = 7;
sprintf(command, "MyCalculator.exe %d", inputValue);
printf("C程序准备执行命令: %s\n", command);
// 2. 使用 popen() 执行命令并打开一个管道来读取输出
FILE* pipe = _popen(command, "r"); // Windows用 _popen
// FILE* pipe = popen(command, "r"); // Linux/macOS用 popen
if (pipe == NULL) {
printf("执行命令失败,\n");
return 1;
}
// 3. 从管道中读取输出
if (fgets(result_buffer, sizeof(result_buffer), pipe) != NULL) {
printf("从LabVIEW.exe捕获到的输出: %s", result_buffer);
// 在这里你可以解析 result_buffer 来提取数值
// 如果输出是 "Result: 49",你可以用字符串处理函数提取 "49"
}
// 4. 关闭管道
_pclose(pipe); // Windows用 _pclose
// pclose(pipe); // Linux/macOS用 pclose
return 0;
}
- 编译和运行
- 将
main_cli.c和MyCalculator.exe放在同一目录下。 - 编译
main_cli.c。 - 运行
main_cli.exe,它会启动MyCalculator.exe,并打印出结果。
- 将
方法对比与选择
| 特性 | 方法一 (调用DLL) | 方法二 (命令行调用) |
|---|---|---|
| 性能 | 非常高,函数直接在进程内调用,开销极小。 | 较低,需要创建新进程,进行进程间通信,开销大。 |
| 复杂度 | 较高,需要理解DLL、函数指针、数据类型映射。 | 非常低,只需了解如何执行命令和读取文本流。 |
| 数据交互 | 灵活,可以传递复杂数据结构(通过LabVIEW的簇、变体等映射)。 | 受限,通常只能通过字符串传递简单数据,解析复杂结构困难。 |
| UI交互 | 无,被调用的LabVIEW VI通常是无界面(后台运行)的。 | 可以,LabVIEW EXE可以带自己的UI运行。 |
| 适用场景 | 需要高性能、频繁调用的集成,如硬件控制、实时数据处理。 | 快速原型验证、简单的脚本式任务调用、或LabVIEW程序必须保留其UI时。 |
- 追求性能和深度集成:选择 方法一,这是专业工程应用的标准做法。
- 追求简单和快速实现:选择 方法二,它非常直观,适合不太复杂的场景。
对于大多数需要将LabVIEW作为计算引擎嵌入到更大C/C++项目中的情况,方法一(调用DLL)是无可争议的最佳选择。
