当前位置: 首页 > news >正文

exptern “C“的作用,在 C 和 CPP 中分别调用 openblas 中的 gemm 为例

 openblas提供的sgemm有两种方式,一种是通过cblas,另一种是直接声明并调用 sgemm_

其中,cblas方式是更正规调用方法;

1,调用openblas的 sgemm 的两种方式

1.1 c语言程序中使用 sgemm

hello_sgemm.c

#include <stdlib.h>
#include <stdio.h>//#define CBLAS_USE 1 #ifdef CBLAS_USE
#include "cblas.h"
#else
//extern "C"{void sgemm_( char * const transpa,  char * const transpb, int *m, int *n,int *k, float *alpha, float *a, int *lda, float *b, int *ldb,float *beta, float *c, int *ldc );
//}
#endifvoid init_matrix(int M, int N, float* A, int lda, int seed)
{srand(seed);for(int i=0; i<M; i++){for(int j=0; j<N; j++){A[i + j*lda] = (float)rand()/RAND_MAX;}}
}void print_matrix(int M, int N, float* A, int lda)
{for(int i=0; i<M; i++){for(int j=0; j<N; j++){printf(" %7.4f ", A[i + j*lda]);}printf("\n");}
}int main()
{int M = 3;int N = 3;int K = 3;float* A = NULL;float* B = NULL;float* C = NULL;int lda = M;int ldb = K;int ldc = M;A = (float*)malloc(lda*K* sizeof(float));B = (float*)malloc(ldb*N* sizeof(float));C = (float*)malloc(ldc*N* sizeof(float));init_matrix(M, K, A, lda, 2023);	printf("\nA =\n"); 	print_matrix(M, K, A, lda);init_matrix(K, N, B, ldb, 2024);	printf("\nB =\n");	print_matrix(K, N, B, ldb);init_matrix(M, N, C, ldc, 2025);	printf("\nC =\n");	print_matrix(M, N, C, ldc);float alpha = 1.0f;float beta = 0.0f;
#ifdef CBLAS_USEcblas_sgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, M, N, K, 1.0, A, lda, B, ldb, 0.0, C, ldc);printf("C = alpha*A*B + beta*C =cblas_sgemm()=\n");	print_matrix(M, N, C, ldc);
#elsesgemm_("N", "N", &M, &N, &K, &alpha, A, &lda, B, &ldb, &beta, C, &ldc);printf("C = alpha*A*B + beta*C = sgemm_()=\n");	print_matrix(M, N, C, ldc);
#endifreturn 0;
}

运行效果:

$ gcc -DCBLAS_USE  hello_sgemm.c -L ../tdd/third-party/openblas/local/lib/ -lopenblas -o hello_sgemm_c
$ gcc  hello_sgemm.c -L ../tdd/third-party/openblas/local/lib/ -lopenblas -o hello_sgemm_c

 

可见调用 sgemm_() 与调用 cblas_sgemm() 的结果相同;

需要注意sgemm_()函数的声明方式,参数全部都是指针:

void sgemm_( char * const transpa,  char * const transpb, int *m, int *n,
                  int *k, float *alpha, float *a, int *lda, float *b, int *ldb,
                      float *beta, float *c, int *ldc );

1.2 cpp 语言程序中调用 sgemm

相较于 c 语言中,cpp 程序中增加了 extern "C"{ 修饰;

否则编译无法通过,由于c++的特性。

hello_sgemm.cpp

#if CBLAS_USE
#include "cblas.h"
#else
extern "C"{void sgemm_( char * const transpa,  char * const transpb, int *m, int *n,int *k, float *alpha, float *a, int *lda, float *b, int *ldb,float *beta, float *c, int *ldc );
}
#endif

 

2. cpp 中的sgemm_声明为何需要 extern "C"

extern "C" 的作用:

       在 C++ 源代码文件中,使用 extern "C" 的作用是告诉编译器按照 C 语言的方式对函数进行链接,而不是 C++ 的方式。这在与其他语言或库进行交互时非常有用,特别是在 C++ 代码中调用 C 语言编写的函数时。


        当您使用 extern "C" 修饰一个函数声明时,编译器会按照 C 语言的命名约定来生成函数符号,这样可以确保 C++ 代码和 C 代码之间的函数调用能够正确链接。在 C++ 中,函数名可能会经过名称修饰(name mangling)以支持函数重载和其他特性,比如在函数末尾加上参数类型缩写,而 C 语言没有这种面向对象的语法概念和需求。

如下图可见,

print_matrix函数的名字,在 cpp中被加了前缀和后缀,而 c语言文件中,函数名字依然为

print_matrix

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • (el-Date-Picker)操作(不使用 ts):Element-plus 中 DatePicker 组件的使用及输出想要日期格式需求的解决过程
  • oracle库PASSWORD_VERSIONS 对应的加密方式
  • 三大浏览器Google Chrome、Edge、Firefox内存占用对比
  • 【复旦微FM33 MCU 外设开发指南】系统篇——时钟
  • java 基础知识一
  • 国产数据库备份恢复实现
  • 在图片URL后面添加一个参数以清理缓存
  • [Unity实战]Mirror网络与Addressable场景管理
  • 多租户系统数据隔离方案
  • 深入理解SQL中的窗口函数
  • Android顶部标题栏自定义,添加按钮
  • springboot多媒体内容管理系统-计算机毕业设计源码08580
  • Linux学习笔记:Linux基础知识汇总(个人复习版)
  • 2435. 矩阵中和能被 K 整除的路径(leetcode)
  • 详解Xilinx FPGA高速串行收发器GTX/GTP(5)--详解8B10B编解码
  • 〔开发系列〕一次关于小程序开发的深度总结
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • JavaScript 基础知识 - 入门篇(一)
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • Making An Indicator With Pure CSS
  • ng6--错误信息小结(持续更新)
  • node-glob通配符
  • vue:响应原理
  • vuex 笔记整理
  • 百度地图API标注+时间轴组件
  • 技术胖1-4季视频复习— (看视频笔记)
  • 你真的知道 == 和 equals 的区别吗?
  • 深度学习在携程攻略社区的应用
  • 说说动画卡顿的解决方案
  • 一个完整Java Web项目背后的密码
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • (003)SlickEdit Unity的补全
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (2022 CVPR) Unbiased Teacher v2
  • (6)设计一个TimeMap
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (阿里云万网)-域名注册购买实名流程
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (二)原生js案例之数码时钟计时
  • (四)Android布局类型(线性布局LinearLayout)
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (转)IOS中获取各种文件的目录路径的方法
  • .net 托管代码与非托管代码
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • .py文件应该怎样打开?
  • @JSONField或@JsonProperty注解使用
  • [ IOS ] iOS-控制器View的创建和生命周期
  • [001-03-007].第07节:Redis中的管道
  • [1159]adb判断手机屏幕状态并点亮屏幕
  • [Android] Android ActivityManager
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [C++] 统计程序耗时
  • [C++]模板与STL简介
  • [java基础揉碎]方法的重写/覆盖