multi-language verification (二)C/C++基础梳理

前言

在开始后续篇幅之前,梳理一下C/C++的语法知识点;对于嵌入式开发或者软件开发的人来说,C/C++并不陌生。但对于SV”选手“来说,这是前期最大的”障碍“。本篇侧重梳理,授之以渔的方式,不会详细解读某一个点。

准备

  • 验证使用C/C++主要是造case和当作胶合语言,不是开发语言,建议抛开厚厚的书,找一些快速上手的资源,例如:🔗菜鸟教程C++ 🔗菜鸟教程C
  • C/C++相比SV,多了一些内存,指针,编译链接的概念,C语言贴近CPU硬件,C++的OOP也比SV"灵活"很多。参考🔗Linux C编程一站式学习 🔗C++基础教程
  • 借助Chatgpt,🔗Copilot等AI辅助,有时提供的代码甚至可以复制直接使用。
  • 学习好的开源代码,遇到问题整理学习,从实际code出发。

GCC编译选项

GCC编译流程参考🔗g++编译详解

选项说明
LIBRARY_PATH开发时,设置LIBRARY_PATH,以便gcc能够找到编译时需要的动态链接库。和编译时链接库 -Ixx`` -Lxx作用类似
LD_LIBRARY_PATH发布时,设置LD_LIBRARY_PATH,以便程序加载运行时能够自动找到需要的动态链接库。和运行时链接库-Wl,-rpath作用类似
-o 直接生成可执行文件
-O/-O1/-O2/-O3优化代码,减少代码体积,提高代码效率,但是相应的会增加编译的时间
-O0关闭优化
-DMACRO以字符串"1"定义 MACRO 宏。
-DMACRO=DEFN以字符串"DEFN"定义 MACRO 宏。
-g 生成调试信息。GNU 调试器可利用该信息
-IDIRECTORY指定额外的头文件搜索路径DIRECTORY。
-LDIRECTORY指定额外的函数库搜索路径DIRECTORY。
-lLIBRARY连接时搜索指定的函数库LIBRARY。
-Wno-deprecated-declarations关闭 使用弃用方式导致的警告,关闭其他警告-Wnoxxx
-Wall开启编译器的所有警告选项
-Wl,-rapth=xxx如果在非标准位置安装了自定义库,可以使用-rpath确保程序找到它们 -Wl : l 为linker缩写
-Xlinker -rpath=xxx和-Wl类似,只不过-Wl需要一个逗号 -Xlinker -rpath -Xlinker xxx 也可以,没有 等于号
-Wl,-E选项告诉链接器在生成共享库时将所有符号都导出,即使它们没有被显式引用
-lmThe flag to link the math library.
-std=c++2a -std=c++11c++2a (C20) -std=c++11 (C11) gcc9默认采用-std=c++14
-shared -fPIC生成共享库
-rdynamic在生成可执行文件时将所有符号添加到动态符号表中-LDFLAGS -rdynamic xxx.so
-DFLAGS -DVCS手动编译uvm库,编译uvm_dpi.cc时,需要加上vendor的define
--verbose显示详细的编译链接过程

C语言

参考https://blog.csdn.net/Holden_Liu/article/details/122541993

CPP

ItemCPPSystemVerilog
宏定义#define LENGTH 10 ,LENGTH使用宏define LENGTH 10, `LENGTH使用宏
类型转化静态转化 foat f = static_cast<float>(int_i);
动态转换 Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base);
C++还存在const_cast 可以突破 C/C++ 的常数限制,修改常数的值
静态转化 num = int'(name);
动态转化 $cast(child_handle, parent_handle);
类的多态,父类句柄指向子类实例
externextern 是用来在另一个文件中声明一个全局变量或函数。C++中extern用于声明,然后还有定义和初始化;C++相比SV,多了一层文件的概念,多个文件中,A文件要使用B文件定义的变量/函数,可以使用extern引用;变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。当使用多个文件且只在其中一个文件中定义变量时(定义变量的文件在程序连接时是可用的),变量声明就显得非常有用。您可以使用extern关键字在任何地方声明一个变量。虽然可以在 C++ 程序中多次声明一个变量,但变量只能在某个文件、函数或代码块中被定义一次。extern指用于在类外定义(function,task,不会是变量)
SV变量的声明和定义在一起;
SV的方法也可以先声明,再调用,最后在定义
SV的编译是一整个filelist,C的每个file都可以单独编译,最后在统一链接到一起,所以C多了一个文件的概念。
staticstatic指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用static修饰局部变量可以在函数调用之间保持局部变量的值。
static修饰符应用于全局变量时, 会使变量的作用域限制在声明它的文件 内。
static静态变量,区别于动态automatic变量,调用完成后,内存不释放;(默认class内的都是automatic的类型,module内的都是static类型)
static一般放在class…endclass中;
C++和sv的static变量都可以通过::访问,但是C++的static变量只能在类外初始化;
函数中的变量定义变量可以放在块 {…}中,也可以不放在其中,没有强制要求;但是会影响作用域;SV函数中的变量声明,必须放在开头位置;否则需要放在begin…end
const常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量;
整数常量:215u
布尔常量:true,false
define预处理器 定义常量:#define LENGTH 10
字符串都是常量
函数头部的结尾加上 const 表示常成员函数,这种函数只能读取成员变量的值,而不能修改成员变量的值;此时如果仍要修改变量的值,需要类型限定符mutable修饰
const:分为两种:全局性、instance性的 (const 在run-time阶段,而 localparam需要在elaboration-time被赋值)
全局性const:在声明时即赋值,之后不可修改;
instace性const:只使用const进行声明,赋值发生在new()中const修饰的变量,不允许被修改,否则编译器报错。
传参传值调用 : 把参数的实际值复制给函数的形式参数,修改函数内的形式参数不会影响实际参数。void swap(int x, int y)
指针调用: 把参数的地址赋值给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。void swap(int *x, int *y)
引用调用:类似sv中的ref;void swap(int &x, int &y)
后两种调用,修改形式参数会影响实际参数
sv默认对变量/数组采用传值调用,对类采用引用;
ref可以显示对变量/数组采用引用的方式;
数组C++一般通过指针操作数组;
C++ STL标准模板库中提供vector来定义数组,拥有更多成员函数
string字符串看成一个数组,声明成指针变量,需要加上const修饰,否则char str = “ABC”; //ISO C++ forbids converting a string constant to ‘char
char site[7] = {‘R’, ‘U’, ‘N’, ‘O’, ‘O’, ‘B’, ‘\0’}; cout << site << endl; site类似python中的string形式,可以单独通过index引用
C++中#include ,则可以像sv一样,使用关键字string声明字符串,同时也可以像python一样,支持str1+str2的连接
SV中的字符串通过string声明
handle1.数组的指针就是数组名,但是这是一个常量指针
2.&array[xx]:取址 int *ptr:声明int类型指针变量;*ptr:解引,取值; ptr+1:增加地址为对应类型的空间大小;
3.函数返回指针类型的变量时,因为函数调用结束时,会释放内存,所以需要static或者动态分配内存new()来保证;
有指针概念,但是没有指针变量的概念;
引用引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字; 引用的可读性比指针高
int& r = i; 引用变量,&区别于取址符号;
引用变量在定义时就必须初始化;当作形参可以不初始化;
ref类似,但是只能用于方法的形参中,没有引用变量的概念;
class访问修饰符:public,protected,private;默认是private,可以修饰变量或者函数
继承也分为三种,public继承,protected继承,private继承;class B : public A,class B : protected A,class B : private A
this指该类,this->的形式访问
类的instance名访问成员,通过’.‘访问;类的指针访问成员,通过’->'访问,和结构体指针访问类似;
构造函数,就是类的名字;构造函数是无返回类型的,也不需要加void修饰;
析构函数:在不在需要该类时,会自动调用析构函数释放内存。
拷贝构造函数:class_type a = b; 进行赋值时,会自动调用拷贝构造函数,所以a和b的object内存不一样
友元函数:略
内联函数:inline,如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。
int getage() const; const成员函数,const 成员函数可以使用类中的所有成员变量,但是不能修改它们的值
C++在声明类时,Box Box1(3.3, 1.2, 1.5); 就自动创建了类的实例;如果是声明了一个类指针,则需要像sv一样调用new手动分配内存。
C++支持一个类中相同名字函数的重载,也支持重载运算符
多态:需要virtual修饰,动态调用;父类加上virtual,子类可以不用再加,和sv一样
sv中默认不加就是public
只有一种类型的继承
class_type a = b; 在sv中,a,b指向同一个实例object
构造函数new(),没有析构函数;C++中的new指动态分配内存;
this.的形式访问
sv中Box Box1只是声明了句柄,还需要调用new()函数创建实例;
sv不支持函数重载,运算符重载;sv只有重写(覆盖); 🔗重写、覆盖、重载区别和存在的意义_c++覆写的意义
多态使用和C++类似,virtual修饰;
命名空间namespace:命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。
using namespace std;using类似sv中的import
package 和 import 管理作用域
模板类似一种忽略类型的宏定义函数或者宏定义类;C++是一种强类型语言,所以引入模板增加灵活性,属于泛型编程(Generic Programming)sv也有类似的,参数化的class;但是C++的更灵活
::C++中::是域操作符,前面什么都不写代表的是全局函数,例如 ::sc_core::sc_module_name"🔗Systemverilog 作用域解析运算符 ::

从C++11开始,引入了一些新的语法和特性,比如autostd::movestd::unique_ptr等,这些特性使得 C++11 成为一个更现代、更强大的编程语言。🔗ModernSystemC一个可参考的example,建议逐步采用C++11特性。

Debug

undefine问题

undefine问题是最常见的,在编译或者运行时遇到,undefined symbol,undefined referenc to,cannot open shared object file等。SV的编译是吃进一整个filelist,然后在elaboration阶段统一link链接,生成可执行程序。而C/CPP是可以提前将一个或者一些文件编译为一个静态或者动态库,最后统一做链接生成target文件。在一个文件调用程序,程序的定义在另一个lib实现,如果gcc无法找到对应程序的定义,则会报undefine问题。

一般是PATH,GCC选项,scope的设置问题,总结如下:

  1. 确保调用的虚函数有实现,才可以被调用

  2. 确认LIBRARY_PATHLD_LIBRARY_PATH的设置符合预期

  3. 确认GCC版本以及-std=指定的C++版本

  4. g++编译的c code使用extern “c”修饰

  5. 使用DPI时,c code调用SV export function,确保svSetScope()符合预期

  6. 如果在elaboration阶段通过vcs link共享库,是否吃进相应的.so文件

  7. 如果在runtime阶段调用共享库,确保使用-sv_lib-sv_liblist方式加载 .so文件

  8. 常用定位命令:
    strings -a <binary> | grep "GCC:" :查看编译时的GCC版本

    ldd -r <binary>: 模拟运行时需要动态链接的库

    nm -g <binary>: 查看符号表,前面带U(undefined)表用在其他库定义

    nm -D <binary> | c++filt | grep <string>:查找匹配string的可读形式函数名

    readelf -d <binary>: 查看依赖的共享库,rpathsoname

Segmentation Fault

TODO

Stack Overflow

TODO

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Holden_Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值