C++语言

《第六篇》llama.cpp:纯 C/C++ 实现的大语言模型推理引擎详解 llama.cpp是一个纯C/C++实现的大语言模型推理引擎,由Georgi Gerganov开发。它通过量化技术将模型压缩为4bit/5bit/8bit等低精度格式,显著降低内存占用,使LLaMA等大模型能在消费级CPU上高效运行。项目采用自定义GGUF格式、优化KV缓存管理、多线程加速和SIMD指令等技术提升性能,支持LLaMA、Mistral等多种开源模型。具备跨平台、无需GPU依赖、内存占用低等特点,适合本地推理、嵌入式设备部署等场景,是隐私敏感型应用和教学研究的理想选择。 阅读详情

0. 课程目标

学多深?以被面试官问到的深度为参考。

按照cppreference中对c++知识的梳理,本材料依照下图中的树形结构分门别类记录知识点。
在这里插入图片描述
其中黄框内的特性是c++11起支持的,将在这个博客中单独呈现;
其中容器库内容很多,将在这个博客中单独呈现;

所以本博客主要学习语言和头文件部分;
头文件的内容很少,不单独做大标题,放在基本概念中;
本文仅包含下列内容:
在这里插入图片描述

1. 头文件

c++中头文件引入方式是尖括号不带后缀,例如: 等等,因为系统头文件也会互相引用,因此不必include全,一般用clion等IDE也会自动提示。

对于一些形式为 xxx.h 的 C 标准库头文件,C++ 标准库同时包含同名的头文件和拥有形式 cxxx 的头文件。

尖括号or双引号?

  • 使用 “xxx.h”,告诉编译器,从当前工作目录开始查找;
  • 使用<xxx.h>,告诉编译器,从系统默认目录中去查找;
  • 若 #include “” 查找成功,则遮蔽 #include <> 所能找到的同名文件;

搜索顺序?

  • 当前目录
  • -I指定的目录
  • gcc的环境变量CPLUS_INCLUDE_PATH(C程序使用的是C_INCLUDE_PATH)
  • gcc的内定目录:/usr/include,/usr/local/include,/usr/lib/gcc/x86_64-redhat-linux/4.1.1/include

用户头文件的编写要注意防御式申明,防止头文件反复引用,官方的称呼是“Conditional inclusion”。

// xx.h
#ifndef __SOMETHING__
#define __SOMETHING__
...
#endif

2. 预处理器

预处理器在编译前的翻译阶段执行。

  • 有条件编译源文件的某些部分(由 #if、#ifdef、#ifndef、#else、#elif 和 #endif 指令控制); 编译开关
  • 替换文本宏,同时可能对标识符进行拼接或加引号(由 #define 和 #undef 指令与 # 和 ## 运算符控制); 函数工厂
  • 包含其他文件(由 #include 指令控制);
  • 由实现定义的行为(由 #pragma 指令控制);

2.1 define宏

#define 标识符 替换列表(可选) (1)
#define 标识符( 形参, … ) 替换列表(可选) (C++11 起) (2)
(1)仿对象宏,注意#define只是简单机械的替换,注意展开后的语义,尽量加括号保护
(2)仿函数宏,以标识符中的括号为特征

2.2 标识符拼接

字符串化
仿函数宏中,如果替换列表 中一个标识符前有 # 运算符,则该标识符在运行形参替换的基础上以引号包围,实际上创建一个字符串字面量。另外,预处理器为内嵌的字符串字面量(若它存在)外围的引号添加反斜杠以进行转义,并按需要双写字符串中的反斜杠。移除所有前导和尾随空白符,并将文本中间(除内嵌字符串字面量中间外)的任何空白符序列缩减成单个空格。此操作被称为“字符串化”。

另外,#@表示加单引号;

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // 展开成 puts("")
showlist(1, "x", int); // 展开成 puts("1, \"x\", int")

标识符拼接
如果 替换列表 中任何两个相继标识符之间有 ## 运算符,则这两个个标识符(首先未被宏展开)在运行形参替换的基础上将结果进行拼接。此操作被称为“拼接”或“记号粘贴”。

// 制造函数工厂并使用它
#define FUNCTION(name, a) int fun_##name() { return a;}

2.3 pragma

优点:头文件标准防护中,必须保重宏名唯一,#pragma once使得错误地在多个文件中使用相同的宏名变得不可能。
缺点:#pragma once 的文件是基于其文件系统层次的身份所排除的,所以若头文件在项目中有多个位置,则这不能防止包含它两次。

3. 关键字

3.1 new/delete

c中malloc()、freee()是函数,分配堆内存;
c++中new、delete是操作符;分别进行2步操作:
1.内存的分配,2.构造函数的调用;
3.析构函数的调用,4.内存的销毁。

void* operator new(size_t size);
void* operator new[](size_t size);
void  operator delete(void *p);
void  operator delete[](void *p);

简言之,new和delete不仅承载着内存分配的功能还承载着对象构造/析构函数的调用功能。
new和delete对内存分配的功能实际上还是由调用malloc()/free()实现。

c++中delete和delete[]要注意甄别,申请内存数组时,new type[num]会记住申请了几个对象,delete[]会据此多次调用析构函数。举个栗子。

3.2 template/typename/typedef/using

template
模板是==泛型编程==的基础,例如我们常使用的vector a;就是用int类型实例化类模板。

常见用法:函数模板、类模板;

template<class T>
template<typename T>

两者没有本质区别,早期没有typename关键字,现在更推荐用typename;
T只是占位符,用其他名称代替也行。

类模板,即class中有些数据类型用T指代:

template<typename T>
class A {
public:
	A(T r = 0) : re(r) {}
private:
	T re;
	...
};
A<double> a1(0.4);

函数模板,编译器会自动进行实参推导(argument deduction);

stone r1(2,3), r2(3,4), r3;
r3 = min(r1, r2);
template<class T>
inline const T& min(const T&a, const T&b) {return b < a ? b : a;}

typedef
创建能在任何位置替代(可能复杂的)类型名的别名。

// 避免必须写 "struct C" 的常见 C 手法
typedef struct {int a; int b;} S, *pS;

typedef与#define的区别。

using/namespace
namespace包含系统库文件内置的命名空间、用户自定义的命名空间;
c++11起支持inline命名空间;

using 指令:using namespace spaceX;
从 using 指令之后到指令出现的作用域结尾为止,命名空间spaceX内的任何名字均可见。
using 声明:using spaceX::nameY;
令来自命名空间 spaceX 的符号 nameY 对无限定名字查找可见。

using 别名 = 原先类型;
using还可以做到:alias templates,比typedef更强大,也更直观。

3.3 decltype/auto

decltype (C++11 起)
检查实体的声明类型,或表达式的类型和值类别。
若实参为无括号的标识表达式或无括号的类成员访问表达式,则 decltype 产生以此表达式命名的实体的类型。
如果对象的名字带有括号,则它被当做通常的左值表达式,从而 decltype(x) 和 decltype((x)) 通常是不同的类型。

decltype(a->x) y;       // y 的类型是 double(其声明类型)
decltype((a->x)) z = y; // z 的类型是 const double&(左值表达式)

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // 返回类型依赖于模板形参
{                                     // C++14 开始可以推导返回类型
    return t+u;
}

auto (C++11 起)
类型说明占位符。
用模板实参推导的规则推导类型。
占位符 auto 可伴随如 const 或 & 这样的修饰符,它们参与类型推导。

auto a = 1 + 2;            // a 的类型是 int
decltype(auto) c1 = a;   // c1 的类型是 int,保有 a 的副本
decltype(auto) c2 = (a); // c2 的类型是 int&,为 a 的别名

// auto 常用于无名类型,例如 lambda 表达式的类型
auto lambda = [](int x) { return x + 3; };

auto会忽略引用,其次,auto一般会忽略掉顶层const,但底层const会被保留下来,比如当初始值是一个指向常量的指针时:

int i = 0;
const int ci = i, &cr = ci;  //ci 为整数常量,cr 为整数常量引用 
auto a = ci;     // a 为一个整数, 顶层const被忽略
auto b = cr;     // b 为一个整数,顶层const被忽略
auto c = &ci;    // c 为一个整数指针.
auto d = &cr;    // d 为一个指向整数常量的指针(对常量对象区地址是那么const会变成底层const)

如果你希望推断出auto类型是一个顶层的const,需要明确指出:

const auto f = ci; // f 为 const int类型

decltype与auto的区别
decltype在处理顶层const和引用的方式与auto有些许不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)。

decltype与auto的联系

// 在其所调用的函数返回引用的情况下
// 函数调用的完美转发必须用 decltype(auto)
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}

3.4 volatile/mutable/const/constexpr

volatile
adj. [化学] 挥发性的;不稳定的;爆炸性的;反复无常的

const 与 volatile统称为“CV”类型限定符。

1.易变性:volatile告诉编译器,某个变量是易变的,当编译器遇到这个变量的时候,只能从变量的内存地址中读取这个变量,不可以从寄存器、或者其它任何地方读取。
2.顺序性:两个包含volatile变量的指令,编译后不可以乱序。注意是编译后不乱序,但是在执行的过程中还是可能会乱序的,这点需要由其它机制来保证,例如memory- barriers(带有lock前缀的指令)。

volatile atomic lock 对比?

mutable
容许在即便包含它的对象被声明为 const 时仍可修改声明为 mutable 的类成员。

const struct
{
    int n1;
    mutable int n2;
} x = {0, 0};      // 带 mutable 成员的 const 对象

// x.n1 = 4; // 错误:const 对象的成员为 const
x.n2 = 4; // ok,const 对象的 mutable 成员不是 const

const
const指定该类型的对象不可修改;

非静态成员函数是声明于类的成员说明中,不带 static 或 friend 说明符的函数。
仅可用于非静态成员函数的额外语法元素:final 与 override 说明符,纯说明符(=0),cv 限定符,引用限定符,以及成员初始化列表。

constexpr (C++11 起)
constexpr 说明符声明可以在编译时求得函数或变量的值。 允许程序利用编译时的计算能力,也有编译变慢的代价。
然后这些变量和函数(若给定了合适的函数实参)即可用于仅允许编译时常量表达式之处。
用于对象或非静态成员函数 (C++14 前)声明的 constexpr 说明符蕴含 const。
用于函数声明的 constexpr 说明符或 static 成员变量 (C++17 起)蕴含 inline。
若函数或函数模板的任何声明拥有 constexpr 说明符,则每个声明必须都含有该说明符。

3.5 static

用来控制变量的存储方式和可见性。
静态成员函数在class内部申明,但必须在class外部定义。
static 关键词仅与静态成员在类定义中的声明一同使用,但不与该静态成员的定义一同使用;
静态成员函数不能为 virtual、const 或 volatile。
静态数据成员不能为 mutable。
静态数据成员可以声明为 inline。 inline 静态数据成员可以在类定义中定义,而且可以指定初始化器。它不需要类外定义。
静态数据成员可以声明为 const(且非 volatile)。它可以直接在类定义内初始化,也可以在类外定义。
合理的单例模式:

class A {
public:
	static A& getInstance();
	setup() {...}
private:
	A();             //构造
	A(const A& rhs); //拷贝构造
	...
};

A& A::getInstance()
{
	static A a;      //被调用时才唯一一次创建
	return a;
}

3.6 inline

内联函数,在函数调用的地方,编译器会直接替换成函数体,减少因函数调用产生的开销。

完全在 class/struct/union 的定义之内定义的函数,无论它是成员函数还是非成员 friend 函数,均为隐式的内联函数。
声明有 constexpr 的函数是隐式的内联函数。

这一点功能上类似于宏展开,但是比宏展开好的地方是,inline发生在编译阶段,会做类型检查,消除了宏展开可能带来的语义隐患。

3.7 const_/static_/reinterpret_/dynamic_cast

c++类型转换分为显式类型转换和隐式类型转换。
隐式类型转换
凡是在语境中使用了某种表达式类型 T1,但语境不接受该类型,而接受另一类型 T2 的时候,会进行隐式转换(T1转换为T2类型),具体是:

  • 调用以 T2 为形参声明的函数时,以该表达式为实参;
  • 运算符期待 T2,而以该表达式为操作数;
  • 初始化 T2 类型的新对象,包括在返回 T2 的函数中的 return 语句;
  • 按语境转换
    将表达式用于 switch 语句(T2 为整型类型);
    将表达式用于 if 、while、for控制、:首个操作数、逻辑运算(T2 为 bool)。
    delete 表达式的实参(T 是任何对象指针类型)。
  • 数组到指针转换
  • 数值提升

仅当存在一个从 T1 到 T2 的无歧义隐式转换序列时,程序良构(能编译)。

显式类型转换
遇到 C 风格转型表达式时,C++编译器尝试将它解释成下列转型表达式,以此顺序:const_/static_/reinterpret_cast。
为什么要设计成C++风格的显式类型转换?编译器优化+规范程序员。

const_cast
语法:A = const_cast(B)
这个运算符可以用来去除一个对象的const或volatile属性,但仍无法修改原值。typeA必须是一个指针或者引用。

static_cast
是最常用到的转化操作符,使用它可以消除因产生类型转化而可能产生的编译器warnings,static_cast全部用于明确定义的变换,包括编译器允许我们做的不用强制转换的“安全”变换和不太安全但清楚定义的变换。static_cast包含的转化类型包括典型的非强制类型转换、窄化变化(会有信息丢失)、void*与T*转换、隐式类型变换和类层次的静态定位(基类和派生类之间的转换)。

dynamic_cast
语法:A=dynamic_cast(B)
TypeA必须是类的指针、类的引用或者void *;
dynamic_cast一般只在继承类对象的指针之间或引用之间进行类型转换。如果没有继承关系,则被转化的类具有虚函数对象的指针进行转换。

reinterpret_cast
语法:A = reinterpret_cast(B)
这是一种最不安全的转换,最有可能出现问题, 不考虑前后是否具备转换的条件(如A*与B*,int与指针…)。

#include <iostream>
class Complex{
public:
    Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ }
public:
    operator double() const { return m_real; }  //类型转换函数
private:
    double m_real;
    double m_imag;
};
int main(){
	Complex c(12.5, 23.8);
    //下面是正确的用法
    double real= static_cast<double>(c);  //调用类型转换函数
   
    //下面的用法是错误的
    //float *p3 = static_cast<float*>(p1);  //不能在两个具体类型的指针之间进行转换
    //p3 = static_cast<float*>(0X2DF9);  //不能将整数转换为指针类型

    return 0;
}

3.8 private/protected/public/friend

带继承情况下,组合结果为基类保护级别和继承方式中级别更高者(级别private>protected>public)。
private
只能由1.该类中的函数、2.其友元函数访问。
不能被任何其他访问,该类的对象也不能访问。

protected
可以被1.该类中的函数、2.其友元函数、3.子类的函数访问。
但不能被该类的对象访问。

public
可以被1.该类中的函数、2.其友元函数、3.子类的函数、4.该类的对象访问。

friend
友元函数包括3种:设为友元的普通的非成员函数;设为友元的其他类的成员函数;设为友元类中的所有成员函数。
友元关系不对称(我说你是朋友,那你可以来访问我;但我不能访问你)。
友元关系不传递(你朋友的朋友不是你的朋友)。
友元关系不继承(你朋友的孩子不是你的朋友)。

3.9 virtual/override/final

virtual 说明符之虚基类
对于每个指定为 virtual 的不同基类,最终派生对象中仅含有该类型的一个基类子对象。多级虚继承时每次都用virtual指定,最终才会只有一份基类。

virtual 说明符之虚函数
指定非静态成员函数为虚函数并支持动态调用派发。
当使用基类的指针或引用来处理派生类时,对被覆盖的虚函数的调用,将会调用定义于派生类中的行为。这种函数调用被称为虚函数调用或虚调用。当使用有限定名字查找(即函数名出现在作用域解析运算符 :: 的右侧)时,虚函数调用被抑制。

若某个成员函数 vf 在类 Base 中被声明为 virtual,且某个直接或间接派生于 Base 的类 Derived 拥有一个下列几项与之相同的成员函数声明:函数名、形参列表(但非返回类型)、cv 限定符、引用限定符,则类 Derived 中的此函数亦为虚函数(无论其声明中是否使用关键词 virtual)并覆盖 Base::vf(无论其声明中是否使用单词 override)。

具有相同名字但不同形参列表的函数并不覆盖同名的基类函数,但会隐藏它:在无限定名字查找检查派生类的作用域时,查找找到该声明而不再检查基类。

struct B { virtual void f(); };
struct D : B { void f(int); // D::f 隐藏 B::f(错误的形参列表)};
struct D2 : D { void f(); // D2::f 覆盖 B::f(它不可见也不要紧)};
 
int main()
{
    B b;   B& b_as_b   = b;
    D d;   B& d_as_b   = d;    D& d_as_d = d;
    D2 d2; B& d2_as_b  = d2;   D& d2_as_d = d2;
 
    b_as_b.f(); // 调用 B::f()
    d_as_b.f(); // 调用 B::f()
    d2_as_b.f(); // 调用 D2::f()
 
    d_as_d.f(); // 错误:D 中的查找只找到 f(int)
    d2_as_d.f(); // 错误:D 中的查找只找到 f(int)
}

要覆盖的 Base::vf 不需要可见(可声明为 private,或用私有继承继承)。

每个虚函数都有其最终覆盖函数,它是进行虚函数调用时所执行的函数。

虚析构函数
虽然析构函数是不继承的,但若基类声明其析构函数为 virtual,则派生的析构函数始终覆盖它。这使得可以通过指向基类的指针 delete 动态分配的多态类型对象。

override说明符
指定一个虚函数覆盖另一个虚函数。

区别于重载,重载指函数标识符不完全相同;

final说明符
指定某个虚函数不能在子类中被覆盖,或者某个类不能被子类继承。

3.10 =delete/=0/default/explicit

=0
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。
称带有纯虚函数的类为抽象类。

=delete弃置函数
delete除了内存管理的功能外,还具有弃置函数的功能。

default
default除了switch语句中的兜底功能外,还具有令编译器为某class生成特殊成员函数(big six)的功能。

explicit 说明符
指定构造函数或转换函数为显式,即,它不能用于隐式转换和复制初始化。
只可出现于在类定义之内的构造函数或转换函数 (C++11 起)的 声明说明符序列 中。

只有一个不带默认值的形参的构造函数,按规范来写,必须带上explicit说明符。
默认构造函数
复制构造函数
移动构造函数
复制赋值运算符
移动赋值运算符
析构函数

3.11 struct/class/this

C++中的 struct 和 class 基本是通用的,唯有几个细节不同:

  • 使用 class 时,类中的成员默认都是 private 属性的;而使用 struct 时,结构体中的成员默认都是 public 属性的
  • class 继承默认是 private 继承,而 struct 继承默认是 public 继承
  • class 可以使用模板,而 struct 不能

this指针

class A{
int x;
public:
    void setA(int x) {
        this->x = x; // 如果用x=x,则仍然值没有变
    }
};

若成员函数有 cv 限定,则 this 的类型是 cv X*(指向同一 cv 限定的 X 的指针)。

3.12 void/void*/nullptr (C++11 起)

void
是不完整类型,可以作为函数返回值类型,可以有指向void的指针void*,可以指示函数不接受形参。

nullptr
是指针字面量,存在从 nullptr 到任何指针类型及任何成员指针类型的隐式转换。

NULL是宏:

#define NULL 0
#define NULL nullptr // C++11 起

4. 表达式

4.1 值类别

在这里插入图片描述

lvalue, 左值指明一个函数或对象。举例而言,如果E是指针类型的表达式,那么*E就是指向了对象或函数的一个左值。另一个例子是,调用一个返回值是左值的结果依旧是一个左值。

xvalue, 它也指向一个对象,通常已经接近了它生存期的结束。(这样一来,它的资源即将被移动)xvalue是包含了右值引用特定类型表达式的结果。(例子:调用返回值为右值引用的结果是一个xvalue)

glvalue, generalized lvalue, 是指更泛化意义上的左值,包含了以前的一部分右值。即lvalue和xvalue的集合。

rvalue, 可以是一个xvalue, 一个临时对象,或临时对象的子对象,或者是一个没有和对象关联的值。

prvalue, pure right value, 纯右值,即不是xvalue的rvalue (举例:调用函数返回值并不是引用类型的结果是一个纯右值。字面量12.7, 3e5, 或者true, 都是纯右值。)

特殊表达式
static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象,并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof… 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)

5. 申明

5.1 引用

引用

  • 引用必须被初始化为指代一个有效的对象或函数。
  • 不存在 void 的引用,也不存在引用的引用。
  • 引用类型无法在顶层被 cv 限定;声明中没有为此而设的语法,而若将限定性添加到 typedef 名、 decltype 说明符或类型模板形参,则忽略它。
  • 引用不是对象;它们不必占用存储。
  • 因为引用不是对象,故不存在引用的数组,不存在指向引用的指针,不存在引用的引用:

& 与 &&
分别为左值引用和右值引用;

左值引用用于建立既存对象的别名,亦可用于在函数调用中实现按引用传递语义;

右值引用可用于为临时对象延长生存期(注意,左值引用亦能延长临时对象生存期,但不能通过左值引用修改它们);

std::string s1 = "Test";
// std::string&& r1 = s1;           // 错误:不能绑定到左值

std::string& r2 = s1 + s1;         // okay:到 const 的左值引用延长生存期
// r2 += "Hjj";                    // 错误:不能通过左值引用修改

std::string&& r3 = s1 + s1;      // okay:右值引用延长生存期
r3 += "Test";                    // okay:能通过到非 const 的引用修改

更重要的是,当函数同时具有右值引用和左值引用的重载时,右值引用重载绑定到右值(包含纯右值和亡值),而左值引用重载绑定到左值:

void f(int& x) {
    std::cout << "lvalue reference overload f(" << x << ")\n";
}
 
void f(const int& x) {
    std::cout << "lvalue reference to const overload f(" << x << ")\n";
}
 
void f(int&& x) {
    std::cout << "rvalue reference overload f(" << x << ")\n";
}
 
int main() {
    int i = 1;
    const int ci = 2;
    f(i);  // 调用 f(int&)
    f(ci); // 调用 f(const int&)
    f(3);  // 调用 f(int&&)
           // 若不提供 f(int&&) 重载则会调用 f(const int&)
    f(std::move(i)); // 调用 f(int&&)
 
    // 右值引用变量在用于表达式时是左值
    int&& x = 1;
    f(x);            // 调用 f(int& x)
    f(std::move(x)); // 调用 f(int&& x)
}

右值引用与move
右值引用的性质允许在适当时机自动选择移动构造函数、移动赋值运算符和其他具移动能力的函数(例如 std::vector::push_back())。

因为右值引用能绑定到亡值,故它们能指代非临时对象:

int i2 = 42;
int&& rri = std::move(i2); // 直接绑定到 i2
std::cout<<i2<<"  "<<rri<<std::endl; // 42 42

i2 = 300; // 注意:虽然用了std::move,i2还能接着用
std::cout<<i2<<"  "<<rri<<std::endl; // 300 300

rri = 999;
std::cout<<i2<<"  "<<rri<<std::endl; // 999 999

6. 初始化

7. 函数

7.1 Lambda表达式

构造闭包:能够捕获作用域中的变量的无名函数对象。

8. 类

9. 模板

GCC和G++有什么区别?c++和g++程序的区别?GCC只能编译C语言吗?gcc 1.cpp和g++ 1.cpp有什么区别? gcc命令不止能编译C语言,还可以编译C++(内部等同于调用g++)或Fortran等(编译其它语言相当于调用对应语言的编译器),g++只能编译C或者C++.如果仅仅考虑C语言,参考此公式:g++ == gcc -xc++ -lstdc++ -shared-libgcc. 阅读详情

相关推荐

探索GGUF:利用llama.cpp高效运行大型语言模型

llama.cpp是一个基于C/C++的库,旨在无需依赖任何外部框架,直接在本地或云环境中高效运行各种大型语言模型。这一项目由Georgi Gerganov开发,他之前也成功开发了其他开源项目,如针对OpenAI的Whisper模型的绑定。

chen的博客 3584

C++_开发_预处理器指令_条件编译_等说明_了解

C++_开发_预处理器指令_条件编译_等说明_了解

qq_44681788的博客 1689

最新版谷歌浏览器Axure插件(免翻墙)

本文介绍了在Chrome浏览器无法直接打开Axure导出HTML文件的解决方法。由于国内网络限制无法访问Chrome商店,需手动下载安装AxureRP扩展插件(提供百度网盘下载链接)。安装步骤包括:1)启用开发者模式;2)拖拽CRX文件或加载解压文件夹;3)勾选"允许访问文件网址"。同时还提示若浏览器版本过低可能无法正常运行,并给出了浏览器升级方法。该教程详细说明了从插件安装到浏览器升级的完整解决方案。

OldCat先生 2971

C++11后面引入的新特性(一)

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录 前言 一、pandas是什么?#pandas_23 二、使用步骤 1.引入库 2.读入数据 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文

全栈工程师 1161

AUTOSAR CAN通信全过程

首先,从AUTOSAR架构上来说,一个完整的CAN通信的过程涉及到了包括硬件、AUTOSAR中间件和上层应用层软件;在硬件部分来说,涉及到的是CAN 总线和CAN的收发器;软件部分的话,涉及到的概念是MCAL(微控制器抽象层)、BSW(基础软件层)、RTE(实时运行环境)、APPL(应用层)等;其中MCAL部分用到了通信驱动模块,而BSW部分使用到了通信服务模块和通信硬件抽象模块;由于笔者是做MCAL和BSW的,至于应用层部分的知识就暂且不具体介绍了;

xxdw1992的博客 6249

Springboot项目中使用邮箱验证码注册登录的代码实现

本文介绍了在Spring Boot应用中实现邮箱验证码注册和登录功能的完整方案。文章首先概述了三种用户认证方式(邮箱验证码注册/登录和传统密码登录),然后详细说明了实现所需的技术栈(Spring Boot、Spring Security、JWT等)。重点阐述了邮件服务配置、验证码生成与存储的核心实现,包括QQ邮箱授权码获取、Thymeleaf邮件模板处理以及验证码缓存管理。最后展示了发送验证码和用户注册的API实现,为开发者提供了完整的参考方案。该方案兼顾安全性和用户体验,适合现代Web应用的用户认证需求。

BXCQ_xuan的技术专栏 | 实战干货·实践教程·学习笔记 1337

【C++ 程序设计】第 1 章:C++ 语言简介

C++ 语言简介:发展简史、特点、程序结构。C 语言是 C++ 语言的前身,在进一步扩充和完善 C 语言的基础上得到了 C++ 语言, 它是 C 语言的继承,尽量兼容 C 语言,加入了面向对象的特征,C++ 语言相对于 C 语言的最根本的变化是引进了类和对象的概念。

顾三殇 —— 博客空间(软件测试) 6823

配置VS Code使用Linux服务器上的Matlab

0、需求 Linux服务器上安装有Matlab 无图形界面,只能使用命令行工具,编辑文件不方便 1、VS Code插件安装 在扩展商店中搜索matlab,会出现Matlab Extension Pack,里面有整理好的matlab扩展 这里只安装了第一排的三个扩展 2、设置(Windows、Mac的设置类似,只是不同系统的文件路径不同) 安装好扩展,重启VS Code后,进行设置 打开:文件→首选项→设置(或快捷键ctrl+,),搜索matlab,结果如下图所示;直接打开完整json配置文件(图

赵彬的博客 5008

C++语言简介

C++语言的发展简史 C++是由贝尔实验室1979年在C语言的基础上开发成功的。C++兼容C语言,用C语言写的程序基本上可以不加修改地用于C++C++对C的“增强”表现在两个方面: (1)在原来面向过程的机制基础上,增强了C语言对类型的处理。 (2)增加了面向对象的机制。C++语言是一种编译式的、通用的、大小写敏感的编程语言,完全支持面向对象的开发模式。 C++语言的特点 一、基本的输入/输出 在C语言中,标准的键盘输入和屏幕输出功能分别使用scanf()和printf(...

LYQ 3万+

电容DAC版图布局中的对称艺术:从二维共质心到误差最小化

本文深入探讨了电容DAC版图布局中的对称艺术,重点介绍了二维共质心技术如何有效最小化误差。通过分析系统误差和随机误差的来源,详细解析了共质心布局的核心技术及优化策略,包括梯度误差补偿和寄生参数平衡方法。实战案例展示了该技术在12位SAR ADC设计中的应用效果,为高精度集成电路设计提供了重要参考。

weixin_29300241的博客 578

Apache Flink连载(一):Apache Flink是什么?

Apache Flink 是一个框架和分布式处理引擎,用于在。

qq_32020645的博客 1215

C++ 语言简介

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。

君逍遥o 1964

图文详解Trae配置Java开发环境

本文介绍了Trae开发工具的安装配置流程:首先从官网下载安装Trae,然后安装Java开发所需的Extension Pack for Java和Spring Boot Extension Pack插件。关键步骤包括修改settings.json配置文件,需指定JDK路径、Maven可执行文件路径和用户设置文件路径。所有操作均配有图示说明,并强调要替换为实际电脑路径。

谷哥的小弟 5987

终极指南:如何使用UTF8-CPP库轻松解决C++多语言编码问题

UTF8-CPP库是一个简单、轻量级的C++头文件库,专门用于处理UTF-8编码的字符串转换和验证。对于需要在C++项目中支持多语言文本的开发者来说,这个库提供了完美的解决方案,能够快速解决编码转换的难题。 ## 🚀 什么是UTF8-CPP库? UTF8-CPP是一个专门为C++开发者设计的**UTF-8编码处理库**,它让你能够在不同编码格式之间进行无缝转换。无论是处理中文、日文、韩文还是

gitblog_00866的博客 445

基于Python的车牌识别系统实现

本文将以基于Python的车牌识别系统实现为方向,介绍车牌识别技术的基本原理、常用算法和方法,并详细讲解如何利用Python语言实现一个完整的车牌识别系统。

商务合作 / 项目定制 / 学习交流。个人vx:lovely_wml 5万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

c++语言程序的后缀,c++中后缀名.c 与.cpp的区别?

ITMISS二者区别如下:.c 是c语言的源程序,.cpp是c++语言的源程序,这是两种不同的语言,语法不同。但是c++兼容c语言的绝大部分语法特性,所以该段代码在C++中可以运行,但是在C语言中就会报错。想要在C中运行,可以将定义变量放置在函数开头,修改后程序段如下:#includevoid main(){int a;a=7;float x,y,z;x=2.5;y=4.7;z=x+a...

weixin_34766614的博客 3278

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

C语言--C++调用C语言程序、C语言调用C++程序

1、C++中调用C语言程序 main.cpp文件 #include <iostream> #include "cfun.h" using namespace std; int main() { cout << "C++ Hello world!" << endl; cfun(); return 0; } #if 0 ou...

tyustli 757

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

yaml-cpp Unicode完全指南:C++项目中多语言文本解析的终极解决方案

yaml-cpp 是一个强大的 C++ YAML 解析器和生成器,特别在处理 Unicode 和多语言文本方面表现出色。作为符合 YAML 1.2 规范的完整实现,它能够无缝处理全球各种语言的字符编码,为C++开发者提供了国际化应用程序开发的终极解决方案。 ## 🚀 为什么选择yaml-cpp处理Unicode? **yaml-cpp 内部使用 UTF-8 编码存储所有字符串**,这意味着无

gitblog_00423的博客 1084

c语言中.cpp英文全称,请问在c++中后缀名.c 与.cpp的区别?

qq_遁去的一_1二者区别如下:.c 是c语言的源程序,.cpp是c++语言的源程序,这是两种不同的语言,语法不同。但是c++兼容c语言的绝大部分语法特性,所以该段代码在C++中可以运行,但是在C语言中就会报错。想要在C中运行,可以将定义变量放置在函数开头,修改后程序段如下:#includevoid main(){int a;a=7;float x,y,z;x=2.5;y=4.7;z=x+...

weixin_34884417的博客 2729

spacy-cpp:C++中的自然语言处理利器

spacy-cpp:C++中的自然语言处理利器 项目介绍 spacy-cpp 是一个为 NLP(自然语言处理)库 spaCy 提供的 C++ 封装库。该项目不属于 spaCy 官方项目,但是遵循同样的 MIT 开源协议。spacy-cpp 的主要目标是让 C++ 应用程序能够使用 spaCy 的强大功能,并提供一个与 spaCy 类似的 API,使得 Python 开发者可以快速开发,并轻松地将项...

gitblog_00981的博客 323

Alpaca-cpp(羊驼-cpp): 可以本地运行的 Alpaca 大语言模型

本文简要介绍 Alpaca-cpp,可以使用本地电脑 CPU 流畅运行大语言模型 Alpaca/LLaMA 的 C++/C 框架。

珍妮的选择的博客 5464

python语言创始人、cpp创始人_Python 与 C++ 语言

C++ 语言是对 C 语言的扩展,两者常被视为一个整体,集成于同一编译环境之中——你只须将一个 C 程序的文件后缀由 .c 改为 .cpp,它就成了 C++ 程序。C++ 在 C 语法之上增加了许多高级特性,运行效率相近而更加灵活多变,因此其应用领域也更为广阔。Cpp.png下面来看一个 C++ 程序示例 myclass.cpp——这段源码首先包含了 C++ 标准库的“输入输出流”头文件,能够更方...

weixin_39685674的博客 245

CPP=C++

CPP = c plus plus =C++

天天的优快云 1143

C语言.c文件调用C++ 中cpp文件中的类

C文件部分: #include "bbb.h"  //包含相应的头文件 test(param0,param1);//在合适的地方调用函数 -------------------------------------分割线------------------------------------------------------------------ 头文件部分:声明的函数在C文件和CPP文...

仗劍走天涯 8601

c语言cpp编译,C和C++混合编译

1. 背景为了工作需要,在抽离一个开源库组件的时候,编译成功链接却失败,查找原因发现测试文件使用的是C++语言,而库的组件使用的是C语言,具体原因记录与此。2. 现场为了测试,写了一个单独的简单案例:新建win32工程,建立三个文件,分别是test.c、test.h和main.cpp。main.cpp#include "test.h"int main(){test(1);return 0;}tes...

weixin_28880469的博客 905

第一章 C++语言简介之——c++语言的特点

C++语言与C语言相比,在求解问题方法上进行的最大改进是。Windows环境下,由C++源程序文件编译而成的。

run__ning的博客 623
上一篇: 【cs229】吴恩达MachineLearning-2/2
下一篇: 【侯捷】C++11
BesiseB
博客等级 码龄14年 92粉丝 34原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值