关于c:C语言程序设计C程序设计的初步认识

<article class=“article fmt article-content”><h2>简略C语言程序的形成和格局</h2><pre><code class=“C”>/求矩形面积/#include “stdio.h"int main() { double a, b, area; a = 1.2; /将矩形的两条边长别离赋给a和b/ b = 3.6; area = a * b; /计算矩形的面积并贮存到变量area中/ printf(“a=%f,b=%f,area=%f\n”, a, b, area);}</code></pre><ol><li>C语言规定必须用main作为主函数名,每一个可执行的C程序都必须有且只有一个主函数</li><li>C程序中的每一条执行语句都必须用分号完结</li><li><p>正文内容必须放在符号“/”和“/”之间,在正文之间不能够再嵌套“/”和“/”</p><h2>标识符、常量和变量</h2></li></ol><p><strong>标识符</strong></p><ol><li>由字母、数字和下划线组成,并且第一个字符必须为字母或下划线</li><li><p>类别</p><ol><li>关键字</li><li>预约义标识符</li><li>用户标识符</li></ol></li></ol><p><strong>常量</strong></p><ol><li>程序运行中,其值不能被扭转的量</li><li><p>分类</p><ol><li><p>整型常量:只用数字示意,不带小数点</p><ol><li>短整型常量</li><li>长整型常量</li></ol></li><li>实型常量:必须带小数点的数</li><li>字符常量</li><li>字符串常量</li></ol></li></ol><p><strong>符号常量</strong></p><pre><code class=“C”>/计算圆面积/#include “stdio.h”#define PI 3.14159 /定义符号名PI为3.14159/int main() { double r, s; r = 5.0; s = PI * r * r; printf(“s=%f\n”, s);}</code></pre><p><strong>变量</strong></p><ol><li><p>变量指程序运行过程中其值能够扭转的量</p><h2>整型数据</h2></li></ol><h3>整型常量</h3><ol><li>整型常量能够用十进制、八进制和十六进制等模式示意</li><li>八进制数:结尾必须是数字“0”</li><li>十六进制数:应用“0x”或“0X”结尾;十六进制数中的字母a、b、c、d、e、f既能够小写也能够大写</li><li><p>在C程序中,只有十进制数能够是正数,而八进制和十六进制数只能是负数</p><h3>整型变量</h3></li><li><p>基本型的整型变量用类型名关键字int进行定义</p><pre><code class=“C”>int k;int i, j, k;int i = 1, j = 0, k = 2;</code></pre><h3>整型数据的分类</h3></li><li>短整型(short int)</li><li>根本整型(int)</li><li>长整型(long int)</li><li>无符号型(unsigned):无符号整数在数的开端加上字母后缀u或U;若是长整型无符号整型常量,加上后缀lu或LU</li></ol><blockquote>若不指定变量为无符号型,则变量隐含为有符号型(signed)</blockquote><h3>整数在内存中的贮存模式</h3><ol><li>通常把一个字节的最左边一位称为最低位,最右边一位称为最高位。对于一个有符号整数,其中最高位用来寄存整数的符号,称为符号位。若是正整数,最高位搁置0;若是负整数,最高位搁置1</li><li>负整数在内存中以“补码”模式寄存</li></ol><p><strong>例</strong>:取二进制数10000101(十进制数-5)的补码<br/>步骤如下:求原码的反码。把原码除符号位之外的二进制码按位取反,得11111010</p><pre><code> 把所得的反码加1,失去原码的补码。得11111011</code></pre><blockquote><p>把内存中以补码模式寄存的二进制码转化成十进制的负整数</p><ul><li>先对除符号位之外的各位取反</li><li>将所得二进制数转换成十进制数</li><li>对所求得的数再减1</li></ul></blockquote><h2>实型数据</h2><h3>实型常量</h3><ol><li><p>小数模式:必须要有小数点</p><h3>实型变量</h3></li><li><p>单精度型(float)</p><ol><li>定义:<code>float a,b,c;</code></li><li>占4字节的存储单元</li></ol></li><li><p>双精度型(double)</p><ol><li>定义:<code>double x,y,z;</code></li><li>占8字节的存储单元</li></ol><h2>算数表达式</h2><h3>根本的算数运算符</h3></li><li>加(+)</li><li>减(-)</li><li>乘(*)</li><li>除(/)</li><li>求余(%):运算对象只能是整型</li></ol><blockquote><ul><li>这些运算符须要两个运算对象,称为双目运算符</li><li>“+”和“-”也可用作单目运算符,运算符必须呈现在运算数的右边</li><li>如果双面运算符两边运算数的类型统一,则所得后果的类型与运算数的类型统一</li><li>如果双目运算符两边运算数的类型不统一,零碎将主动进行类型转换,使运算符两边的类型达到统一后再进行运算</li><li>在C语言中,所有实型数的运算均以双精度形式进行</li></ul></blockquote><h3>运算符的优先级、联合性和算数表达式</h3><ol><li>算数运算符的优先级</li><li><p>算数运算符和圆括号的联合性</p><ol><li>以上运算符中,只有单目运算符“+”和“-”的联合性是从右到左的,其余运算符的联合性都是从左到右</li></ol></li><li><p>算数表达式</p><ol><li>定义:用算术运算符和一对圆括号将运算符(或称操作数)连接起来的、合乎C语言语法的表达式</li><li>运算对象能够是常量、变量和函数等</li></ol><h3>强制类型转换表达式</h3></li><li><p>格局:<code>(类型名)(表达式)</code></p><ol><li><code>(类型名)</code> 称为强制类型转换运算符</li></ol><h2>赋值表达式</h2><h3>赋值运算符和赋值表达式</h3></li><li>格局:<code>变量名=表达式</code></li><li>赋值运算符的左侧只能是变量,不能是常量或表达式</li><li><p>C语言规定最右边变量中所失去的新值就是赋值表达式的值</p><h3>复合赋值表达式</h3></li><li><p>定义:在赋值运算符之前加上其余运算符</p><h3>赋值运算中的类型转换</h3></li><li>如果赋值运算符两侧的数据类型不统一,在赋值前零碎将主动先把右侧表达式求得的数值按赋值号右边变量的类型进行转换</li><li><p>在C语言的表达式(不包含赋值表达式)中的转换规则</p><ol><li>一个短整型,一个长整型:$短整型 \to 长整型$</li><li>一个是有符号整型,一个是无符号整型:$有符号整型 \to 无符号整型$</li></ol><h2>自加、自减运算符和逗号</h2><h3>自加运算符和自减运算符</h3></li><li>“++”和“–”都是单目运算符,不能给常量或表达式赋值</li><li>既能够前缀模式呈现,也能够后缀模式呈现</li><li>对于变量来说自增或自减1;对于表达式来说,前置先自增后应用变量值,后置先应用变量值再自增</li><li><p>联合方向:从右至左</p><h3>逗号运算符</h3></li><li>联合方向:从左至右</li><li>逗号运算符优先级最低</li></ol></article> ...

March 5, 2024 · 1 min · jiezi

关于c++:C42-类型转换函数-下

类类型是否可能转为一般类型?

March 4, 2024 · 1 min · jiezi

关于c:关系运算符

a+b>c等价于(a+b)>c,a!=b>c等价于a!=(b>c) 依照优先级预处理!=优先级小于>,故等价于a!=(b>c)设a,b,c均为 int 型变量,则执行语句 a=b=3;c=++a||++b;后,b 的值为3 解析:预处理c=((++a)||(++b));++a表达式值为4即为真,逻辑或,右边为真左边不计算,呈现短路景象,所以++b没计算,故b的值为3。根本数据类型:整型,字符型,浮点型整型常量:示意模式有八进制(以0结尾),十进制,十六进制(以0X结尾)短整型:short 2字节,-2^15~2^15无符号短整型:undesigned short 2字节,0~2^16-1联合性:单目运算符,赋值运算符,条件运算符是右联合性字符常量(一般字符和转义字符):用单撇号括起来的一个字符。如’A’,*等。用反斜杠疏导的,具备特定含意的字符,如’\n’,’\367’,’\x8a’。注:C语言字符集中的任何一个字符均可用转义字符来示意。转义字符特色是以”\”作为结尾,前面能够是规定的字母,比方’\n’代表换行,’\’示意反斜线字符,’ 示意逗号字符(,),也能够是1到3位8进制数,或者x加上1到2位十六进制数。

March 4, 2024 · 1 min · jiezi

关于c:Programming-Abstractions-in-C阅读笔记p308p311

《Programming Abstractions in C》学习第76天,p308-p311总结,总计4页。 一、技术总结1.疾速排序伪代码#include <stdbool.h>static int Partition(int array[], int n);/* * Implementation notes: SortIntegerArray * -------------------------------------- * This implementation of SortIntegerArray uses the Quicksort * algorithm, which begins by "partitioning" the array so that * all elements smaller than a designated pivot element appear * to the left of a boundary and all equal or larger values * appear to the right. Sorting the subarrays to the left and * right of boundary ensures that the entire array is sorted. */void SortIntegerArray(int array[], int n) { int boundary; if (n < 2) { return; } boundary = Partition(array, n); SortIntegerArray(array, boundary); SortIntegerArray(array + boundary + 1, n - boundary - 1);}/* * Function: Partition * Usage: boundary = Partition(array, n); * -------------------------------------- * This function rearranges the elements of array relative to * a pivot value, which is taken from array[0]. The partition * function returns a boundary index such that array[i] < pivot * for all i < boundary, array[i] == pivot for i == boundary, * and array[i] >= pivot for all i > boundary. */static int Partition(int array[], int n) { int lh, rh, pivot, temp; pivot = array[0]; lh = 1; rh = n - 1; while (true) { while (lh < rh && array[rh] >= pivot) { rh--; } while (lh < rh && array[lh] < pivot) { lh--; } if (lh == rh) { break; } temp = array[lh]; array[lh] = array[rh]; array[rh] = temp; } if (array[lh] >= pivot) { return 0; } array[0] = array[lh]; array[lh] = pivot; return lh;}2.疾速排序工夫复杂度均匀工夫复杂度:O(NlogN), 最坏工夫复杂度:O(N^2)。 ...

March 2, 2024 · 2 min · jiezi

关于c++:C41-类型转换函数-上

规范数据类型之间会进行因式类型平安转换转换规则如下:char-short-int-unsigned int-long -unsigned long-float-double

February 29, 2024 · 1 min · jiezi

关于c++:记一次使用-Windows-调试套件-gflags-解决-CefSharp-加载报错信息模糊的问题

最近写 CPP 我的项目遇到了一个问题,用了几个工具来解决,这里记录一下,和大家一起探讨。 1. 起因我的一个 CPP 我的项目的 UI 框架应用的是 CefSharp,UI 层是 C#,而一些模块代码应用的是 CPP,运行报错如下 报错信息是 System.IO.FileLoadException:"未能加由"CefSharp.Core.Runtime.dl"导入的过程第一感觉是过程加载某个配置文件或 dll 未胜利,或者动静库版本问题,但错报不进去,而且 VS 的 Debugger 无奈显示更多内容,用 Dependencies 看过程,dll 都是找到了的,那会是什么起因呢? 2. 剖析通过共事的提醒,应用微软提供的 Windows Debugging Tools 调试套件 gflags.exe 工具,让过程加载过程中的日志能在 VS 的<输入>报进去,配置如下。在 Image File 中输出残缺过程名,而后选中 Show loader snaps 显示加载器快照,而后重启过程。 而后从新运行,在 VS 的输入中就能够看到过程加载过程中的日志,如下。 在输入中搜 ERROR,能够看到加载哪些 dll 失败、正告等信息,有一些不重要,持续找发现加载的一个 dbghelp.dll 文件后,应用它的一个函数 SymGetSearchPathW 未找到失败,到库目录发现这个文件的工夫比拟老了,这个办法须要在 6.3 以上版本的 dbghelp.dll 文件才提供。 能够应用 dumpbin 命令的 dumpbin dbghelp.dll /EXPORTS 命令看到这个 dll 里并没有这个SymGetSearchPathW 办法,如下 ...

February 29, 2024 · 1 min · jiezi

关于c:Programming-Abstractions-in-C阅读笔记p303p305

《Programming Abstractions in C》学习第74天,p303-p305总结,总计3页。 一、技术总结1.工夫复杂度分类(complexity classes)ClassNotationExampleconstantO(1)Returning the first element in an arraylogarithmicO(logN)Binary search in a sorted arraylinearO(N)Linear search in an arrayNlogNO(NlogN)Merge sortquadraticO(N^2)Selection sortcubicO(^3)Conventional algorithms for matrix multiplicationexponentialO(2^N)Tower of Hanoi当然,这个分类并不是相对的,只是常见的。 二、英语总结1.substantial是什么意思?答:adj. large in size(sizeable)。p305, Even though the selection sort example makes it cleaar that quadratic algorithms have substantial performance problems (重大的性能问题)for large values of N, algorithms whose complexity is O(2^N) are considerably worse。 2.tractable是什么意思?答:tractare("to handle, manage", treat), adj. easily controlled。p305, As a general rule of thumb(依据教训), computer scientists classify problem that can be solved susing algorithms that run in polynomial time as tractable, in the sense that they are amenable to implementation on a computer。 ...

February 26, 2024 · 1 min · jiezi

关于c:Programming-Abstractions-in-C阅读笔记p293p302

《Programming Abstractions in C》学习第73天,p293-p302总结,总计10页。 一、技术总结1.工夫复杂度(1)quadratic time(二次工夫) p293, Algorithms like selection sort that exhibit O(N^2) performance are said to run in quadratic time。 2.线性查找(linear search)p293, Because the for loop in the implementation executes n time, you expect the performance of LinearSearch——as its name implies——to be O(N)。工夫复杂度为O(N)的查找称为线性查找。 3.归并排序(merge sort)书中并为对归并排序做严格的定义。p298, The merge operation, combined with recursive decomposition, gives rise to a new sorting algorithm called merge sort, which you can implement in straightforward way. The basic idea of the algorithm can be outlined as follows: ...

February 25, 2024 · 3 min · jiezi

关于c:带使能控制的锂电池充放电解决方案

一、产品概述TP4594R 是一款集成线性充电治理、同步升压转换、电池电量批示和多种爱护性能的单芯片电源治理 SOC,为锂电池的充放电提供残缺的单芯片电源解决方案。TP4594R 外部集成了线性充电治理模块、同步升压放电治理模块、电量检测与 LED 批示模块、爱护模块。TP4594R内置充电与放电功率 MOS,充电电流为 250mA,最大同步升压输入电流为 500mA。TP4594R 采纳专利的充电电流自适应技术,同时采纳专利的管制形式省去内部的功率设定电阻,降低功耗的同时升高零碎老本。TP4594R 外部集成了温度弥补、过温爱护、过充与过放爱护、输入过压爱护、输入过流爱护、输入短路爱护等多种平安爱护性能以保障芯片和锂离子电池的平安。TP4594R利用电路简略,只需很少的外围元件便能够实现锂电池充放电的残缺计划,极大的节俭了零碎的老本和体积。二、产品特点线性充电,同步升压集成电源门路治理,反对边充边放最大升压输入电流 500mA充电电流 250mA升压输入 EN 使能管制指示灯敞开对应输入电流 5mA使能敞开时待机功耗低至 2.5uA使能无效时待机功耗低至 25uA充电电流自适应技术智能温度控制与过温爱护反对涓流充电以及零电压充电集成多种爱护性能封装模式:ESOP8L三、产品利用蓝牙耳机充电仓锂电池电子设备其余小功率电源治理利用四、利用阐明线性充电TP4594R 充电时工作在线性充电模式。当电池电压低于2.9V 时,芯片工作在涓流充电状态,涓流充电电流为25mA。当电池电压大于 2.9V 时,芯片进入恒流充电状态,恒流充电电流为 250mA。当电池电压达到 4.2V 时,芯片进入恒压充电状态,充电电流开始逐步减小。当充电电流减小至 60mA 时,线性充电过程实现,芯片进入待机状态。TP4594R 具备智能再充电性能,在待机状态中,芯片监控 BAT 电压,当 BAT 电压降落至 4.0V 时,VDD 从新对电池进行充电,开始新的充电循环。边充边放TP4594R 集成了电源门路治理,反对边充边放性能。在充电电源接入和 OUT 端有负载接入的状况下,TP4594R工作在边充边放模式,线性充电的同时 OUT 端提供电源输入。当充电电源移除后,芯片马上进行同步升压模式,OUT 放弃输入状态。为了进步零碎的可靠性,边充边放模式下,TP4594R 也具备输入过流和短路爱护性能。当输入过流或短路产生时,芯片敞开放电门路,此时充电门路不受影响。当负载移除后,放电门路从新关上,边充边放性能复原。EN 使能管制与低功耗智能待机TP4594R 的同步升压输入具备 EN 使能管制性能。当 EN脚的电压高于 1.5V 时,同步升压输入敞开,芯片工作在低功耗待机状态,芯片待机电流为 2.5uA。当 EN 脚电压低于 0.3V 时,同步升压开始工作,OUT 端为输入状态。此时如果 OUT 端没有接入负载,TP4594R 的工作电流可低至 25uA。TP4594R 外部对 EN 脚没有上拉/下拉性能,当 EN 使能管制性能不必时,需把 EN 脚接到 GND来让同步升压电路工作。TP4594R 的线性充电性能不受EN 脚的高低电平管制。LED 敞开/开启对应的输入电流在 EN 脚电压低于 0.3V 时,同步升压工作,OUT 端为输入状态。当 OUT 的输入电流减小到典型值 5mA 并通过16s 延时后,LED 指示灯敞开。LED 指示灯敞开后,OUT的输入电流再增大到典型值 7mA 并通过 16ms 延时后,LED 指示灯从新开启。电池低压爱护启动时,当 BAT 电压大于 3.15V 时,升压电路开始工作,工作过程中如果电池电压低于 3.05V,则 LED1 会以 2HZ频率快闪揭示电量较低,当电池电压低于 2.85V,则放电输入敞开,TP4594R 进入低电流待机模式。智能温度控制TP4594R 外部集成了温度反馈环路,充电或放电时,如果芯片外部的温度升高到 115℃,充电电流或放电电流会智能的随着芯片外部的温度升高而升高,从而减小零碎功耗以克制温升,爱护芯片不被低温损坏,如果芯片温度升高到 150℃时,芯片进行工作,等到芯片温度升高到130℃后再从新复原工作。爱护性能TP4594R 集成了过充爱护、过放爱护、温度保护、输入过压爱护、输入过流爱护和输入短路爱护等多重爱护性能,以保障芯片和锂离子电池的平安。在利用上也能够额定减少一颗 DW01 来对系统进行双重爱护。TP4594R 的输入短路和过流爱护具备自复原性能。在爱护产生后,把输入移除,芯片可主动复原到失常工作状态。元件抉择1、OUT 输入电容抉择品质较好的低 ESR 的贴片电容,否则会影响输入纹波。2、电感 L1 需采纳功率电感且饱和电流满足利用要求,否则因电感饱和可能会导致芯片工作不失常。PCB 设计参考1、IC 上面敷铜接 GND,地线铺开面积要尽量大,其它不重要的线都能够绕开以满足地线须要。2、BAT 电容既要凑近芯片 BAT 脚又要凑近电感;BAT电容的地线尽量接在大面积地线上,不要通过较小的地线再到芯片和大面积地。3、VDD 电容凑近芯片 VDD 脚,其地线尽量接在大面积地线上,不要通过较小的地线再到芯片和大面积地。4、OUT 输入电容尽量凑近芯片,其地线尽量接在大面积地线上,不要通过较小的地线再到芯片和大面积地。5、电感需凑近 BAT 电容,电感和 BAT 电容以及芯片尽量在同一层不要过过孔,电感到 SW 的走线尽量短而粗。工作状态与电量批示LED1~LED4 为充放电状态与电量批示引脚,不同情况时 LED 状态如下:①接入 VDD 时,LED1 到 LED4 会顺次全副点亮,而后再依据电池电量批示充电状态,达到电量的 LED 灯常亮,以后电量的 LED 以 1Hz 频率闪动,充斥电后 LED1~LED4 全亮;②放电时,LED1~LED4 依据电池电压批示以后电量,若电池电压低于 3.05V,LED1 会以 2HZ 的频率快闪提醒电量低,直到电池电压低于 2.85V,进行放电,进入低功耗低压保护模式,须要从新充电至 3.15V 以上才能够再次放电; ...

February 25, 2024 · 1 min · jiezi

关于c++:C39逗号操作符的分析

逗号操作符逗号操作符(,)能够形成逗号表达式逗号表达式用于将多个子表达式连贯为一个表达式逗号表达式的值为最初一个表达式的值逗号表达式中的前N-1个子表达式能够没有发返回值逗号表达式依照从左向右的程序计算每个子表达式的值#include <iostream>#include <string>using namespace std;void func(int i){ cout << "func() : i = " << i << endl;}int main(){ int a[3][3] = { (0, 1, 2), (3, 4, 5), (6, 7, 8) }; int i = 0; int j = 0; while( i < 5 ) func(i), i++; for(i=0; i<3; i++) { for(j=0; j<3; j++) { cout << a[i][j] << endl; } } (i, j) = 6; cout << "i = " << i << endl; cout << "j = " << j << endl; return 0;}

February 23, 2024 · 1 min · jiezi

关于c++:掌握Linux后端开发岗位技能一本就够

1.缘起大家好,我是《Linux后端开发工程实际》的作者万木春。我发现市面上的Linux后端开发相干书籍大多集中在API手册或运维手册,却鲜有针对后端开发岗位和工程实际的高效学习指南。在我本身学习Linux后端开发的过程中,也曾经验过许多弯路和挫折,因而我萌发了编写一本贴合Linux后端开发岗位和工程实际的书籍的想法。 2.撰稿创作这本书,我冒了很大的危险。我抉择在实现全书的创作之后,再寻找出版社投稿,这无疑减少了被出版社退稿的危险,可能会让我之前的致力化为泡影。 创作过程是最具挑战性的局部,它须要强烈的自律精力和长期的保持。我也曾多次中断创作,然而通过不懈的致力和保持,我最终实现了全书。我的工作经验也是我可能实现这本书的关键因素之一。 作为一个完满主义者,我在创作过程中会常常纠结于代码是否优雅、格调是否对立、是否存在bug、知识点是否齐备等问题,因而我对内容和代码进行了重复的调整和欠缺。 在IO模型与并发那章中,压测工具和17种不同的并发模型的设计并非欲速不达,而是通过屡次思考、推倒重来和迭代才得出的后果。为了获取更精确的压测数据和更稳固的示例程序,我破费了几周的工夫在压测和优化程序上。 在MyRPC框架设计与实现那章中,为了实现一个高性能、易读、构造清晰且代码量适中的RPC框架,我重复实现了四个版本的RPC框架。为了确保RPC框架代码的正确性,我编写了102个单元测试用例,并对RPC框架所有的代码进行了充沛的测试,最初对RPC框架还进行了齐备的性能压测和内存透露的检测。为了更好的治理测试用例,我专门创立了一个excel文档对测试用例进行治理,这个excel文档局部内容下图所示。 为了让读者更好的了解书中的内容,我购买了业余的绘图软件,精心绘制了60多张的图片。秉着实际出真知的准则,在书中有很多常用工具的实现,例如,ping、make、shell、traceroute和arp等命令行工具。通过编码实现常用工具,能够深刻的了解并把握相干的核心技术点。 3.投稿因为稿件品质过硬,且选题独特,在投稿的时候并没有遇到什么大的问题。通过人民邮电出版社的张涛编辑的帮忙,我顺利地与人民邮电出版社签订了出版合同。 4.三审三校三审三校的过程历时8个月,稿件通过了7、8次的重复批改。为了给读者呈现出更好的内容并晋升浏览体验,我十分重视细节,比方代码中是否少了一个空格、正文是否标准、代码缩进是否统一,甚至图片的箭头是否有间隙。我也非常感谢人民邮电出版社的排版和编辑老师,他们不厌其烦地调整书稿,没有他们的辛勤付出,《Linux 后端开发工程实际》就无奈顺利出版。在这期间,张涛编辑还会和我一起探讨书的中英文的命名等细节,他们的工作做得十分粗疏。 5.写在最初《Linux 后端开发工程实际》是一本实用性极强的书,它是市面上少有的能残缺形容如何从 0 到 1 构建 Linux C/C++后端微服务集群的书。通过实际案例和具体的代码实现,读者能够一步步构建出本人的后端微服务集群,从而深刻了解和把握 Linux 后端开发的精华。它将率领您走进 Linux 后端开发的世界,开启您的 Linux 后端开发之旅。让咱们一起摸索 Linux 后端开发的有限可能,独特迎接挑战和时机。 京东购买链接:https://item.jd.com/10096373960488.html 天猫购买链接:https://detail.tmall.com/item.htm?abbucket=7&id=765959625705&... 当当购买链接:https://product.dangdang.com/11702142394.html 拼多多购买链接:https://mobile.yangkeduo.com/goods.html?goods_id=586950483757...

February 23, 2024 · 1 min · jiezi

关于c++:patb1035

#include <iostream>#include <algorithm>using namespace std;int main() { int n, a[100], b[100], i, j; cin >> n; // 输出n个数a和n个数b for (int i = 0; i < n; i++) cin >> a[i]; for (int i = 0; i < n; i++) cin >> b[i]; // 找到b中最大的递增元素的地位 for (i = 0; i < n - 1 && b[i] <= b[i + 1]; i++); // 找到a中与b不同的元素的地位 for (j = i + 1; a[j] == b[j] && j < n; j++); if (j == n) { cout << "Insertion Sort" << endl; // 如果a和b雷同,则是应用插入排序对a进行排序 sort(a, a + i + 2);//插排的性质:[0,i+1]排序 } else { //不是插排则模仿并排 cout << "Merge Sort" << endl; int k = 1, flag = 1; // 如果a和b不同,则是应用归并排序对a进行排序 while(flag) { flag = 0; for (i = 0; i < n; i++) { if (a[i] != b[i]) flag = 1; } k = k * 2; // 对a的每个子数组进行排序 for (i = 0; i < n / k; i++) sort(a + i * k, a + (i + 1) * k); sort(a + n / k * k, a + n); } } for (j = 0; j < n; j++) { if (j != 0) printf(" "); printf("%d", a[j]); } return 0;}依照插入排序两头序列的性质判断是否是插入排序(后面为按序,后边与原数组一样)如果是插入排序,则第i轮完结后前i个数字为已排序,第i+1到开端为原数组 ...

February 23, 2024 · 1 min · jiezi

关于c++:patb1034-有理数的运算

这道题能够说是我目前刷到的patb组里最麻烦的一道题 次要是带分数这玩意曾经记不清多少年都没碰过了,而且各种状况非常容易思考不全 最初靠本人也没写出个能全过的解,起初一看是数太大了而我全程都在用int的问题,能够说是百密一疏…… 这里附上柳神的赏心悦目的c++解法,正文我写的,而后前面的解析由chatglm4生成,不便了解。 #include <iostream>#include <cmath>using namespace std;long long a, b, c, d;// 计算两个数的最大公约数long long gcd(long long t1, long long t2){ return t2 == 0 ? t1 : gcd(t2, t1 % t2);}void func(long long m, long long n){ if (m * n == 0) { printf("%s", n == 0 ? "Inf" : "0"); return; } // 符号判断 bool flag = ((m < 0 && n > 0) || (m > 0 && n < 0)); // 分数化简运算时不思考正负,先取绝对值!! m = abs(m); n = abs(n); long long x = m / n; // 整数位 printf("%s", flag ? "(-" : ""); if (x != 0) printf("%lld", x); if (m % n == 0) { // 判断是否只有整数 if (flag) printf(")"); // 如果是负整数,则补全括号 (正整数没括号) return; } if (x != 0) printf(" "); // x不为0,则输入空格 (且整数的状况已在后面提前返回,不会运行到这) m = m - x * n; // 真分子 long long t = gcd(m, n); m = m / t; n = n / t; // 约分成最简分式 printf("%lld/%lld%s", m, n, flag ? ")" : "");}int main(){ scanf("%lld/%lld %lld/%lld", &a, &b, &c, &d); func(a, b); printf(" + "); func(c, d); printf(" = "); func(a * d + b * c, b * d); printf("\n"); // a/b+c/d通分公式,输入有理化后的后果 func(a, b); printf(" - "); func(c, d); printf(" = "); func(a * d - b * c, b * d); printf("\n"); func(a, b); printf(" * "); func(c, d); printf(" = "); func(a * c, b * d); printf("\n"); func(a, b); printf(" / "); func(c, d); printf(" = "); func(a * d, b * c); return 0;}这段代码是一个C++程序,用于解决分数的加减乘除运算,并且输入后果。程序首先定义了一个计算最大公约数的函数gcd,而后定义了一个解决分数并格式化输入的函数func。主函数main中读取用户输出的两个分数,而后别离计算它们的和、差、积、商,并输入后果。程序应用scanf函数从规范输出读取两个分数,格局为%lld/%lld %lld/%lld,别离对应四个长整型变量a, b, c, d。这里的%lld是读取长整型的格局指定符。func函数是程序的外围,它承受两个长整型参数m和n,别离代表分数的分子和分母。函数首先查看分子或分母是否为0,如果是,则依据状况输入Inf(无穷大)或0。接着,函数解决分数的正负号,并计算分数的整数局部x。而后,函数通过计算最大公约数来简化分数,并依照格局输入分数。在main函数中,程序别离计算了两个分数的和、差、积、商,并调用func函数输入后果。加减运算通过通分后相加或相减来实现,乘法通过分子相乘、分母相乘来实现,除法令是通过分子乘以另一个分数的分母、分母乘以另一个分数的分子来实现。程序的输入格式化得很好,可能解决正负整数和分数,以及它们的运算后果。 ...

February 23, 2024 · 2 min · jiezi

关于c++:LLVM-Debian-Ubuntu-下载安装

LLVM 框架提供多种下载方式: LLVM Download Page (官方网站): https://releases.llvm.org/ LLVM GitHub Release (GitHub 发行版): https://github.com/llvm/llvm-project/releases LLVM For Debian (Debian 下载链接): https://apt.llvm.org/ 本文将应用 LLVM Debian 主动下载安装脚本, 如下图所示 倡议: 下载安装时应该指定具体的 LLVM 版本号, 不要应用最新版本. 示例: 对于 LLVM-18, 应该应用如下 Bash 命令进行下载安装. wget https://apt.llvm.org/llvm.shchmod +x llvm.shsudo ./llvm.sh 18 all装置实现后, 应该在 /usr/bin 目录下见到相似的文件名: ls /usr/bin 这些带有 -18 后缀的可执行文件都是 LLVM 框架的一部分, 兴许某个时候你会用到它们, 但兴许永远都不会用到. 为了使用方便, 咱们能够给这些文件增加硬连贯: ln /usr/bin/FileCheck-18 /usr/bin/FileCheckln /usr/bin/clang-18 /usr/bin/clangln /usr/bin/clang++-18 /usr/bin/clang++ln /usr/bin/llvm-as-18 /usr/bin/llvm-asln /usr/bin/llvm-dis-18 /usr/bin/llvm-disln /usr/bin/llvm-link-18 /usr/bin/llvm-linkln /usr/bin/llc-18 /usr/bin/llcln /usr/bin/lli-18 /usr/bin/lli这样就能够通过 clang example.c 的形式运行名为 example.c 的 C 语言文件了. ...

February 23, 2024 · 1 min · jiezi

关于c++:C38逻辑操作符的陷阱

潜规则操作符只有两种值(true和false)逻辑表达式不能齐全计算就能确定最终值最终后果只能是true或者false逻辑表达式:

February 21, 2024 · 1 min · jiezi

关于c++:C37-智能指针分析

内存泄露动静申请堆空间,用完后不偿还C++语言中没有垃圾回收机制指针无法控制所指堆空间的生命周期例:内存泄露 #include <iostream>#include <string>using namespace std;class Test{ int i; public: Test(int i) { this->i = i; } int value() { return i; } ~Test() { }};int main(){ for(int i = 0;i<5;i++) { Test* p = new Test(i); cout << p->value() <<endl; } return 0;}输入: 01234深度的思考:须要一个非凡的指针指针的生命周期完结时被动开释堆空间一片堆空间最多只能由一个指针标识杜绝指针运算和指针比拟例:智能指针:

February 20, 2024 · 1 min · jiezi

关于c:Programming-Abstractions-in-C阅读笔记p283p292

《Programming Abstractions in C》学习第72天,p283-p292总结,总计10页。 一、技术总结1、anylasis of algorithms算法剖析——即判断程序的效率(efficiency)。 2、mathematical induction(数学归纳法)3、Big-O notation(大O标记法)4、constant time(常量工夫)5、linear time(线性工夫)p292, The computational complexity of the part of the Average function is O(N), which is commonly called linear time。 double Average(double array[], int n) { int i; double total; total = 0; for (i = 0; i < n; i++) { total += array[i]; } return total / n;}二、英语总结1、mission是什么意思?答:c. any work that sb believes it is their duty to do(工作,工作)。p285, Your mission is to write a function SortIntegerArray(array, n) that rearranges the elements into ascending order。 ...

February 20, 2024 · 1 min · jiezi

关于c:Kernel-Compilation-Kernel-Module-System-Call-Implementation

Kernel Compilation, Kernel Module, andSystem Call Implementation1 IntroductionThe objective of this assignment is to familiarize yourself with the Linux kernel source code. Specifically,you will:• Compile your own Linux kernel.• Create your own kernel module.• Add a new kernel system call and then test this system call from a user-space program.All the assignment’s steps must be performed using your Debian virtual machine from programmingassignment 1. The notions from the course involved in this assignment are the following:• Linux source code exploration and compilation.• Installing and running a modified kernel, as well as creating and testing a module.• The printk kernel function.• User space / kernel space communication using a system call.2 Finding and Booting Your “Known Good” KernelStart the Debian VM, log in, open a terminal window, and execute the following command to find theexact version of the kernel you are currently running: uname -rWrite down the result somewhere and remember this exact kernel version for the rest of the semester.This is your “known good” kernel which is known to work correctly. Also execute ls -l /boot and youshould see one “vmlinuz” file in the /boot directory that has the exact same version in its name. This isthe file containing your “known good” kernel. Never delete or modify this file in any way.Use Debian’s battery icon menu (upper right corner of the Debian desktop) to restart the virtual machine.As soon as you see the white-on-blue-green menu of the GRUB boot loader, press the down arrow key onthe keyboard to select the second menu entry named “Advanced options for Debian GNU/Linux”. Youhave only 5 seconds to do this! Then press Enter to get a sub-menu. In the sub-menu, select the “knowngood” kernel, based on the version you learned just above (but not the “recovery mode” one, which issimilar to Microsoft Windows’s “safe mode”, which is not what we want here) and press Enter to bootthis ‘known good” kernel. From now on this is what you will do every time you boot or reboot the VM, tomake sure you always know exactly which kernel you are booting! If later you have a problem when testingyour own modified “working” kernel (see below), such as a kernel that panics (crashes) on boot, you willalways be able to boot this “known good” kernel instead to get back to work.3 Compiling Your Own “Working” Kernel1) Before compiling your own “working” kernel, you must first install some tools and the Linux kernelsource code. So, after booting the “known good” kernel (as indicated above), log in, open a terminalwindow, and execute the following command to install all the software required to configure andcompile the Linux kernel source code:sudo apt install build-essential pahole libelf-dev libncurses-dev libssl-dev flex bison(build-essential is a software package that depends on all the development libraries and headerfiles and basic development tools that you need, so installing it guarantees that all those things arepresent on your VM; pahole and libelf-dev are a set of tools and a library to handle the ELFstandard file format for executable files; libncurses-dev is a library to create text-based userinterfaces, which is used by “make menuconfig” below; libssl-dev is a library that providescryptographic functions and secure networking; and flex and bison are a lexer / scanner generatorand parser generator, respectively).2) Install the Linux kernel source code: sudo apt install linux-sourceThis automatically selects the right version of the Linux kernel source code, based on the version ofthe “known good” kernel which is currently executing on the VM. Then execute ls -l /usr/srcand you should see one file named “linux-source-X.Y.tar.xz” (“tar” is the standard file archive formatfor Unix, and “xz” is one among many compressed file formats on Unix; other common ones are “gz”and “bz2”; together “tar” and “xz” give you a compressed file archive, similar in spirit to the “zip”compressed file archive format which is used a lot on Microsoft Windows).3) Execute cd to make sure that you are in your home directory. Then decompress and extract the kernelsource code you just installed: tar -xavf /usr/src/linux-source-X.Y.tar.xz(the -x option means “extract”; -a means auto-compress or auto-decompress, as the case may be; -v means “verbose”, to see the names of the extracted files as the extraction happens; -f is followedby the name of the compresses archive file). After doing this, you should have in your home directorya new directory named “linux-source-X.Y” (use ls to see it).Use du -s -h linux-source-X.Y to see how big the Linux kernel source code is.4) Change the name of this new “linux-source-X.Y” directory: mv linux-source-X.Y pa25) Execute cd pa2 to move into the top directory of your Linux kernel source code. Use ls to have alook at the different directories there (see slides 20-21 in the “Introduction to Linux” lecture notes onCanvas for an explanation of the content of those directories).6) Next we need to create a configuration file for the kernel (see slides 34 and 36 of the “Introduction toLinux” lecture notes). The simplest method is to just copy and then modify the configuration file forthe “known good” kernel which is currently executing on your VM. Again, the command uname -rtells you exactly which kernel version you are currently executing on the VM, so we can use the resultof this command to copy the right kernel configuration file from the /boot directory into the currentdirectory containing your Linux kernel source code: cp /boot/config-$(uname -r) .config7) We can now modify this kernel configuration file using: make menuconfigYou should then get a text-based user interface (see slide 35 in “Introduction to Linux”) which allowsyou to easily modify your kernel configuration file:a) Press Enter to go into the “General setup” sub-menu, press the down arrow twice on yourkeyboard to go down two lines, then Enter to select “Local version - append to kernel release”. Inthe new text window that appears, enter a minus sign - followed by your login name (which isalso your Stevens login name), followed by “-pa2”. For example: -pmeunier-pa2 (replace mylogin name with yours, obviously). Do not add any space before, inside, or after this text. Thispiece of text is going to be added to the version of the Linux kernel you are going to compile, sothat later you can easily recognize which kernel is yours. This will be your “working” kernel. PressEnter to select “OK” and you should be back in the previous sub-menu, with the text you justtyped is now showing between () parentheses in front of the name of the “Local version - appendto kernel release” sub-menu. Press the right arrow on your keyboard to select “Exit” and thenEnter to go back to the previous top-level menu.b) Select Save and press Enter. In the new window, check that the default “.config” file name iscorrect and press Enter to save your new configuration file. Then select “Exit” to quit the“menuconfig” user interface and go back to the usual Unix shell.c) Double check the differences between the original kernel configuration file and the one you justmodified: diff /boot/config-$(uname -r) .configIn the output you should see that the kernel variable CONFIG_LOCALVERSION is now defined tobe the piece of text “-pmeunier-pa2” (except with your own login name) while before it was theempty string (ignore any change for CONFIG_CC_VERSION_TEXT and for SALT, SIG, and KEY stuff,these changes are irrelevant). You are now ready to compile the Linux kernel source code for your“working” kernel!8) Execute nproc to see how many processors your VM is using (this should be the same number youindicated in the settings of the VM in VirtualBox). The more the better.You might also want to go into the settings of your host operating system (Microsoft Windows orApple macOS) and make sure that the power settings of your computer are set for maximumperformance (for example, in Microsoft Windows, click on the battery icon at the right end of thebottom taskbar, then move the slider to “Best performance”); you can undo this setting later againafter you are finished compiling the kernel.Also make sure that your host OS is not set up to automatically suspend or shut down your hostcomputer if you do not move the mouse or whatnot for a while. Again you can undo this later whenyou are finished compiling the kernel.If you are using a laptop computer, also make sure that it is plugged into an electric socket, otherwiseyour host OS might automatically throttle your computer’s performance to save the battery.Finally, click with your right mouse button on the Debian desktop background, select “Settings”, then“Power”, then click on “Automatic suspend” and turn off both “On Battery Power” and “Plugged In”;this will guarantee that Debian does not suspend itself while you are in the middle of compiling. Thenclose the settings window.Now we are ready to compile the whole Linux kernel source code using all the VM’s processors inparallel, to speed up things: make -j $(nproc) allWait an hour or two (or three). You will know the compilation is over when your computer’s fan stopsmaking more noise than usual… If for some reason you need to stop the compilation before it isfinished, just press Ctrl-c on the keyboard. You can then re-start the compilation later using the samecommand again, and it will automatically restart from where it left off.If for some reason the compilation fails, it might be hard to see why it failed because you are compilingdifferent parts of the kernel code in parallel. In that case, you can execute just make all to restartthe compilation from where it failed but this time in sequential mode on a single CPU, which will makeit much easier to see what the problem is. Then contact your nearest Course Assistant.If you look at the output of the make command while it is compiling the code, you will see differentabbreviations: CC is when compiling a C file to get a “something.o” object file (a file containing binaryCPU instructions), LD is when linking (gluing) multiple object files together, AR is when creating alibrary (a “something.a” archive file of object files, which later will be linked with the rest of thekernel), [M] means that this code is part of a dynamically loadable kernel module, not part of themonolithic Linux kernel proper.9) Execute du -s -h . to see how much disk space the current directory containing the whole compiledLinux source code takes (it should be around 19GB).10) When compiling the kernel, all the kernel modules are also compiled at the same time. We now needto install these new kernel modules: sudo make INSTALL_MOD_STRIP=1 modules_installThis must be done as root (the system administrator) hence the use of “sudo” here. TheINSTALL_MOD_STRIP=1 argument given to the make command tells make to strip extra debugginginformation from the modules when installing them, which saves around 2GB of disk space.Once the modules are installed, you can execute ls -l /usr/lib/modules and you should see inthe output a directory with a name that has your login name and “pa2” at the end, which is where themodules were installed. The command du -s -h /usr/lib/modules/* should show you that allthe different directories there (the one for your own modules, as well as the one for the “known good”kernel) are about 400MB in size.11) Now we can install the new “working” kernel itself: sudo make installDo not worry about any “Please install the Linux kernel "header" files matching the current kernel”message in the command’s output; we would need this only if we were to try to use our Debian VMas the host for another VM on top of it!Execute ls -l /boot and you will see that make installed several files there, all of which have yourlogin name and “pa2” at the end of their name: “config-X.Y…-pmeunier-pa2” which is a copy of the“.config” file you used for compiling your kernel (you can check this using the diff command, forexample; see above), “initrd.img-X.Y…-pmeunier-pa2” which is the kernel’s “initial RAM disk” whichthe kernel only uses at boot time (see here for more information if you are curious), “System.map-X.Y…-pmeunier-pa2” which contains a list of the kernel’s symbols (the function names and variablenames inside the kernel) for your kernel (see slide 44 in “Introduction to Linux” lecture notes), andfinally “vmlinuz-X.Y…-pmeunier-pa2” which is your very own “working” kernel!As part of the kernel’s installation, the configuration file for the GRUB bootloader is also automaticallyupdated so that the bootloader now knows about your new kernel.12) Use Debian’s battery icon menu to restart the virtual machine. Again, as soon as you see the white-on-blue-green menu of the GRUB boot loader, press the down arrow key on the keyboard to selectthe second menu entry named “Advanced options for Debian GNU/Linux”. You have only 5 secondsto do this! Then press Enter to get a sub-menu. In the sub-menu, select now your own “working”kernel, which has your login name and “pa2” at the end of its name (but again not the “recoverymode” one) and press Enter to boot your own kernel. Happiness ensues.13) After booting your own “working” kernel, log in, open a terminal window, use Ctrl-+ to increase thefont size of the terminal window, and execute uname -a (which should show a kernel name withyour own login name and “pa2” at the end of it) and then id. Take a screenshot and save it as a picturesomewhere on your host computer, you will need to submit it later on Canvas (more details aboutthis at the end of this document). Make sure the kernel version and your login name (Stevens loginname) are clearly visible inside the terminal window in your screenshot. For example:Congratulations on compiling and booting your first Linux kernel!Now create in your home directory another new directory that you will use for submitting your assignment(again, use your own Stevens login name): cd; mkdir pmeunier-pa2Then copy your “working” kernel configuration file into your submission directory:cp pa2/.config pmeunier-pa2To finish this part of the assignment, create a backup copy of the kernel source code you just compiled,just in case (-r means to do a recursive copy that will automatically copy the directory, its sub-directories,its sub-sub-directories, etc.; -p preserves the file time stamps when copying which the make commanduses to decide whether to compile a file again or not, so this is important when copying compiled codethat has been created using make; this command takes a couple of minutes to complete because you arecopying about 19GB of data): cp -p -r pa2 pa2-backupLater, when doing the rest of this assignment, if you make a big mistake inside your “pa2” directory, suchas accidentally deleting some files, you can always find the original files inside this backup directory. Inthe worst case, if you do not know how to fix the mistake, you can always completely delete your “pa2”directory (cd; rm -rf pa2) and re-create it using the backup copy (cp -p -r pa2-backup pa2).4 Creating a Kernel ModuleIn your submission directory (cd pmeunier-pa2), create a new directory (mkdir module). In that newdirectory (cd module), write a Linux kernel module in a file named “pmeunier.c” (use your own loginname). This module must have a printk() statement that outputs “Hello World from NAME (LOGIN)” inthe kernel log when the module is loaded into the kernel, where NAME is your full legal name and LOGINis your Stevens login name. When the kernel module is unloaded it must print “PID is XYZ and programname is NAME” where XYZ is the PID number and NAME the program name of the current process. (Seeyour “Introduction to Linux” and “Processes in Linux” lecture notes.)Compile your kernel module using the appropriate “Makefile”. (Make sure that you are still running yourown “working” kernel when doing this!)You must provide a single screenshot that shows two Debian terminal windows side by side: one windowmust show the kernel log (with your module’s output visible in it), and the other window must show theoutput of the uname -a command followed by commands to load-unload your module at least twice (sowe can see in the kernel log that the PID printed when unloading the module changes during each unload).Save the screenshot somewhere on your host computer, you will need to submit it later on Canvas (moredetails about this at the end of this document). For example (partly censored):5 Adding a System Call to Your “Working” Kernel and Testing It5.1 Adding The System CallIn the directory containing the compiled source code of your “working” kernel (cd ~/pa2; “~” is a shellspecial character that always represents your home directory) create a new directory (mkdirmy_syscall). In that new directory (cd my_syscall), in a file named “my_syscall.c”, write the C codefor a new system call named “LOGIN_syscall” (replace LOGIN with your Stevens login name) that takes assingle parameter a pointer to a character array containing a string. Make sure you use the proper C macroto define your system call (see the “System Calls” lecture notes). The code of your system call must alwaysreturn a signed long integer (long) as result.Your system call must do the following:1) If the string pointer given as argument is NULL then your system call must immediately return -1.2) If the string length is larger than 32 (where the string length is its total number of characters, includingthe ’\0’ string terminator character), then your system call must immediately return -1.3) Copy the string from user space to kernel space.4) Use printk to print “before: “ followed by the string. Note: whenever you use printk, always makesure that the string you want to print is terminated with a ‘\n’ newline character, otherwise the stringwill not immediately appear in the kernel logs when your code is executed.5) Replace all occurrences of a lowercase vowel letter (a, e, i, o, u, y) in the string with the first letter ofyour login name, in uppercase (for example, given my “pmeunier” login name, the letters a, e, i, o, u,and y are all replaced with the uppercase letter P).6) Use printk to print “after: “ followed by the modified string.7) Copy the modified string from kernel space to user space.8) The system call then returns as result the number of character replacements performed in step 5.In your code, use the functions listed on slide 25 of the “System Calls” lecture notes as much as possible.Make sure your code properly checks for errors when using each of these functions (see the examplesystem call code on slide 21 in those same lecture notes). Do not use a module to implement your systemcall. Also create a “Makefile” in the same directory (see slide 27).Modify other files in the Linux kernel source code as necessary (see slides 26 and 27; use gettimeofdayfrom slide 21 as an example of how to add your own system call to the various Linux files). Give yoursystem call the number 451. Keep a list somewhere of all the files you modify, because later you will needto copy them to your submission directory.Recompile your “working” kernel, the same way you did it in section 3 of this assignment. Note: some ofthe files you need to modify are referenced throughout the kernel’s code, so, when recompiling, the makecommand then needs to recompile most of the kernel code again, which again takes a very long time. Somake sure you modify the files correctly on the first try, so you do not have to recompile the whole kernelover and over. If you only need to change your my_syscall/my_syscall.c file then recompiling the kernelshould take only about 5 minutes since the rest of the kernel’s code will not need to be recompiled againin this case.If the compilation succeeds then reinstall your “working” kernel and its associated modules (do NOT tryto install anything if the compilation failed!) Note that, when installing your modified “working” kernel,the previous version of your “working” kernel will be renamed with an extra “.old” extension at the endof its name. You can just ignore this one.Reboot the virtual machine and make sure that you use the GRUB bootloader to select the correct kernelwhen rebooting (your “working” kernel with the “-pmeunier-pa2” name, that now contains the code foryour own system call).If your “working” kernel panics (crashes) on boot for some reason, reboot with your “known good” kerneland fix the problem in the code of your “working” kernel.After you have booted the correct kernel, execute the following command to double-check that the kernelyou are now running actually knows about your system call (see slide 44 of the “Introduction to Linux”lecture notes; replace “pmeunier” with your own login name): grep pmeunier /proc/kallsymsIf the output of this command is empty then the current kernel does not know about your system call andso you did something wrong somewhere. Re-read this whole section and try again.5.2 Testing The System CallIn your submission directory (cd ~/pmeunier-pa2), write the C code for a user-space test programcalled “syscall.c” that invokes your system call. Since your system call does not have a corresponding Cwrapper function available in the C standard library, you must directly use the “syscall” function of the Cstandard library to call your system call (see slide 18 of the “OS Concepts and Structure” lecture notes foran example). Your code must invoke your system call twice: once for the case where the string size islarger than 32, and once for the case where the string size is less than 32. In both cases, your C programmust print on the screen:1) The string given to the syscall, before the system call happens.2) The return value of the syscall.3) The string after the system call, even if it has not been modified.Note: you can directly use the system call number 451 in your C code.Important note: the strings that you use in your code must be defined as local variables (the same way itis done for example on slide 18 of the “OS Concepts and Structure” lecture notes), not as string constantsthat you directly give to the system call as argument. This is because, when your code executes inside aprocess, all the string constants from your code are stored in a part of the “data” segment of the process’saddress space which is read-only (since string constants are… constant), which in turn means that yourkernel system call would fail when trying to modify those strings. Local variables are stored in the process’sstack, which is read-write and your system call will then be able to modify those strings.You must provide a single screenshot that shows two Debian terminal windows side by side: one windowmust show the kernel log (with your system call’s output visible in it, when the string given as argumentto the system call is short enough), and the other window must show the output of the uname -acommand followed by the execution of your user-space test program. Save the screenshot somewhereon your host computer, you will need to submit it later on Canvas (more details about this below). Forexample:6 What to Submit For This AssignmentOnce both your system call and your user-space test program work, copy the code of the system call, plusany other kernel file you modified, into your submission directory (your user-space test program mustalready be there): cd ~/pa2; cp -p -r my_syscall … any other file you modified … ~/pmeunier-pa2In the same submission directory, create a PDF file named “screenshots.pdf” that contains:1) Your full name.2) The Stevens Honor pledge.3) The three screenshots you created above: one showing that you compiled your own “working” kernel(section 3), one showing how your kernel module works (section 4), and one showing how your systemcall and your user-space test program work (section 5.2). Make sure the screenshots are clearlyreadable.4) Also add a short explanation before each screenshot so the Course Assistants know what you aretrying to show on those screenshots.At this point the submission directory (“pmeunier-pa2”) must contain all the files you have created ormodified during this assignment (including the kernel .config configuration file, which you can only see inthe submission directory by using the ls -a command). Install the zip program on your virtual machine(sudo apt install zip) and then create a ZIP file of your submission directory (the -r option meansto zip all the subdirectories recursively: do not forget it; also use your own student login name, twice,obviously): cd; zip -r pmeunier-pa2.zip pmeunier-pa2Once you have correctly created the file “pmeunier-pa2.zip”, copy it to the host OS using your sharedfolder, double-check its content to make sure it contains everything, then submit it on Canvas.After the deadline for this assignment has passed, you can delete the backup copy of your “working”kernel: rm -rf ~/pa2-backupIt is up to you whether you delete the compiled source code of your “working” kernel or not (rm -rf~/pa2), you will not need it anymore. You can delete it after the deadline for this assignment has passed,if you want to save VM disk space, or delete it only at the end of the semester, or keep it for ever as asouvenir!Done!7 Rubric1) Correct .config file: 5%2) Screenshot showing the corresponding “working” kernel version: 5%3) Code of module/pmeunier.c: 15%4) Code of module/Makefile: 5%5) Screenshot of kernel log with module loading-unloading (twice): 10%6) Code of my_syscall/my_syscall.c: 25%7) Code of my_syscall/Makefile: 5%8) Code of syscall.c: 15%9) Other modified kernel files: 5%10) Screenshot of kernel log and output of syscall.c: 10%Important note: you do not get points for screenshots unless the corresponding files are submitted too.So for example you will not get points for the first screenshot listed above if you do not also provide thecorresponding .config file. Screenshots alone will not get you any points at all. So make sure you doublecheck everything before you submit on Canvas! ...

February 18, 2024 · 20 min · jiezi

关于c++:C34-数组操作符的重载

字符串类的兼容性string类最大限度的思考了C字符串的兼容性能够依照应用C字符串的形式应用string对象#include <string>using namespace std;int main(){ string s = "a1b2c3d4"; int n = 0; for(int i = 0;i<s.length();i++) { if(isdigit(s[i])) { n++; } } cout << n <<endl; return 0;}输入: 4重载数组拜访操作符数组拜访符是C/C++中的内置操作符数组拜访符的原生意义是数组拜访和指针运算例: #include <iostream>#include <string>using namespace std;int main(){ int a[5]; for(int i=0;i<5;i++) { a[i] = i; } for(int i=0;i<5;i++) { cout << *(a + i) << endl; //cout << a[i] << endl; } cout << endl; for(int i=0;i<5;i++) { i[a] = i+10; //a[i] = i+10; } for(int i=0;i<5;i++) { cout<<*(i+a)<<endl; //cout<< a[i]<<endl; } return 0;}输入: ...

February 17, 2024 · 1 min · jiezi

关于c++:C33-C中的字符串类-string-sstream相关的头文件

解决方案C到C++的进化过程引入了自定义类型在C++中能够通过类实现字符串类型的定义规范库中的字符串类C++语言反对C语言的所有概念C++语言中没有原生的字符串类型C++规范库提供了string类型string间接反对字符串的连贯string间接反对字符串的大小比拟string间接反对子串查找和提取string间接反对字符串的插入和替换 例: #include <iostream>#include <string>using namespace std;void string_sort(string a[], int len){ for(int i=0; i<len; i++) { for(int j=i; j<len; j++) { if( a[i] > a[j] ) { swap(a[i], a[j]); } } }}string string_add(string a[], int len){ string ret = ""; for(int i = 0;i<len;i++) { ret += a[i]+";"; } cout <<endl; return ret;}int main(){ string sa[7] = { "Hello World", "D.T.Software", "C#", "Java", "C++", "Python", "TypeScript" }; string_sort(sa, 7); for(int i=0; i<7; i++) { cout << sa[i] << endl; } cout << endl; cout << string_add(sa, 7) << endl; return 0;}输入: ...

February 16, 2024 · 1 min · jiezi

关于c++:Whats-new-in-Pika-v351

Pika 社区很快乐发表,咱们明天公布曾经过咱们生产环境验证 v3.5.1 版本 https://github.com/OpenAtomFoundation/pika/releases/tag/v3.5.1 。 该版本不仅做了很多优化工作,还引入了多项新性能。这些新性能包含 动静敞开WAL、ReplicationID 检测是否增量复制、在 K8s 环境上 Pika 服务的主动注册从而实现集群的自组织、以及 exporter 检测集群指标等等,无疑将会让用户享受到更为稳固和高效的 NoSQL 应用体验。 1 新个性1 Slow log 减少队列等待时间统计,在队列阻塞的时候不便咱们进行问题定位。PR 1997, 作者 wangshao1。2 主从复制应用 ReplicationID 判断是否进行增量同步,解决原主从同步形式切主后整个数据集会进行全量复制的问题,能够晋升 Pika 性能。PR 1951, 作者 Mixficsol。3 WAL 以 'disablewal' 命令形式反对动静敞开,在写性能遇到瓶颈的时候,能够通过命令敞开 WAL  缓解写性能降落的问题,敞开 WAL 有机器宕机后失落数据的危险,用户须要依据本人的应用习惯衡量。PR 2015,作者 Mixficsol。4 flush 线程数和 compaction 线程数合二为一,在 Compaction 性能瓶颈时,能够动静调整线程数,缓解 Comapction 损耗 Pika 性能的问题。PR 2014, 作者 Tianpingan。5 降级了 RocksDB 版本到 v8.3.3。PR 2000, 作者 dingxiaoshuai123。6 新增周期性打印工作队列的长度性能,在队列阻塞的时候能够疾速定位问题。PR 1978, 作者 Tianpingan。7 新增利用一个 pika_exporter 监测整个集群的指标,实现一个 Pika Exporter 实例监控整个集群,解决了 3.5.0 版本一个 Pika Exporter  监测一个 Pika 实例耗费资源的问题。PR 1953, 作者 chenbt-hz。8 实现在  K8s  环境上  Pika  服务的主动注册,在启动时主动注册,从而实现集群的自组织 ,实现了通过命令拉起整个 Pika Cluster 集群。PR 1931, 作者 machinly。2 bug 修复1 调整了 Rate_limit 参数,修复了压测时呈现 RPS 为 0 的状况 。PR 2009, 作者 Mixficsol。2 修复了 INFODATA 命令中对于遍历数据文件时呈现空门路的逻辑判断。PR 1996, 作者 Mixficsol。3 修复了 Codis 在线上呈现大毛刺的问题。PR 2016, 作者 chejinge。4 修复了 macOS 环境下编译应用 tools 导致编译不过的问题 。PR 2011, 作者 A2ureStone。5 缩小了 exporter 非必要日志的打印,升高 了资源利用率。PR 1945, 作者 Mixficsol。3 应用倡议本次新增了几个配置参数,大家在应用过程中,须要依据应用状况按需调整: ...

September 28, 2023 · 1 min · jiezi

关于c++:学懂现代CEffective-Modern-C之转向现代C

前言古代C++中像auto、智能指针、挪动语义等都是一些重大的优化个性,但也有一些像constexpr、nullptr等等这样一个小的个性。这章的内容就是这些小个性的汇合。 条款7:在创建对象时留神辨别()和{}在古代C++中有3种形式来以指定的值初始化对象,别离时小括号、等号和大括号: int x(0); //初始化值在小括号中int y = 0; //初始化值在等号后int z{0}; //初始化值在大括号中其中,大括号模式的初始化时C++11引入的对立初始化形式。大括号初始化能够利用的语境最为宽泛,能够阻止隐式窄化的类型转换,还对最令人苦恼的解析语法免疫。 先说阻止隐式窄化的类型转换,比方上面代码能够通过编译: double x,y,z;int sum1(x+y+z); //能够通过编译,表达式的值被截断为intint sum2 = x+y+z; //同上而以下代码不能够通过编译,因为大括号初始化禁止内建类型间接进行隐式窄化类型的转换。 int sum3{x+y+z}; //编译不通过再说最令人苦恼的解析语法免疫。C++规定:任何可能解析为申明的都要解析为申明,而这会带来副作用。所谓最令人库娜的解析语法就是——程序员原本想要以默认形式结构一个对象,后果却不小心申明了一个函数。举个例子,我想调用一个没有形参的Widget构造函数,如果写成Widget w();,那后果就变成了申明了一个函数(名为w,返回一个Widget类型对象)而非对象。而用大括号初始化Widget w{};就不存在这个问题了。 然而,不能自觉的都应用大括号初始化。在构造函数被调用时,只有形参中没有任何一个具备std::initializer_list类型,那么大括号和小括号没有区别 ;如果又一个或多个构造函数申明了任何一个具备std::initializer_list类型的形参,那么采纳了大括号初始化语法的调用语句会强烈地优先选用带有std::initializer_list类型形参的重载版本。也就是说,因为std::initializer_list的存在,大括号初始化和小括号初始化会产生天壤之别的后果。 这点最突出的例子是:应用两个实参来创立一个std::vector<数值类型>对象。std::vector有一个两个参数的构造函数,容许指定容器的初始大小(第一个参数),以及所有元素的初始值(第二个参数);但它还有一个std::initializer_list类型形参的构造函数。如果要创立一个元素为数值类型的std::vector(比方std::vector<int>),并且传递两个实参给构造函数,那么应用大括号和小括号初始化的差异就比拟大了: std::vector<int> v1(10, 20); //创立一个含有10个元素的vector,所有元素的初始值都是20std::vector<int> v1{10, 20}; //创立一个含有2个元素的vector,元素的值别离时1,20所以,如果是作为一个类的作者,最好把构造函数设计成客户无论应用小括号还是大括号都不会影响调用得重载版本才好。 条款8:优先选用nullptr,而非0或NULL因为0和NULL都不是指针类型,而nullptr才是真正的指针类型。比方在重载指针类型和整型的函数时,如果应用0或者NULL调用这样的重载函数,则永远不会调用到指针类型的重载版本,只有应用nullptr能力调用到。当然为了兼容咱们依然须要遵循C++98的领导准则:防止在整型和指针类型之间重载。 条款9:优先选用别名申明,而非typedefC++11提供了别名申明来替换typedef,两者作用在大部分状况下是一样的。比方上面的typedef: typedef std::unique_ptr<<std::unordered_map<std::string, std::string>>> UPtrMapSS;typedef void (*FP)(int, const std::string&);能够用上面的别名申明来替换: using UPtrMapSS = std::unique_ptr<<std::unordered_map<std::string, std::string>>>;using FP = void (*)(int, const std::string&);但还有有一种场景是只能应用别名申明的,那就是在定义模板的时候,typedef不反对模板化,但别名申明反对。在C++98中须要用嵌套在模板化的struct里的typedef能力达到雷同成果。比方上面这段: template<typename T>struct MyAllocList { typedef std::list<T, MyAlloc<T>> type; //MyAllocList<T>::type是std::list<T, MyAlloc<T>>的同义词};MyAllocList<Widget>::type lw; //客户代码在C++11中用别名申明就很简略了: template<typename T>using MyAllocList = std::list<T, MyAlloc<T>>; //MyAllocList<T>是std::list<T, MyAlloc<T>>的同义词MyAllocList<Widget> lw; //客户代码这里还能够看到,别名模板能够让人免写“::type”后缀。并且在模板内,对于内嵌typedef的援用常常要求加上typename的前缀,而别名模板没有这个要求。 ...

September 27, 2023 · 1 min · jiezi

关于c++:c-对象在栈上还是在堆上

c++的对象到底在栈上还是调配在堆上?首先,毋庸置疑,应用new和malloc系列函数调配的对象,肯定是在堆上的。 Object *obj = new Object();有争议的是 Object obj;它是在栈上还是在堆上呢? 要答复这个问题,首先咱们须要了解这句话的意思,这句话并不代表在栈上分配内存,它代表的是让obj具备“主动存储(automatic storage)”的性质。所谓的“主动存储”,意思是这个对象的存储地位取决于其申明所在的上下文。如果这个语句呈现在函数外部,那么它就在栈上创建对象,此时obj变量和obj指代的对象(此时obj实质上其实是obj指代对象的首地址)都在栈上。如果这个语句不是在函数外部,而是作为一个类的成员变量,则取决于这个类的对象是如何调配的。思考上面的代码: class Test{ Object obj;}Test *test = new Test;test指针是在栈上,它所指代的对象Test是存在堆上,那么obj变量和obj对象就在堆上。 class Test{ Object obj;}Test test;test变量在栈上,test对象在栈上,那么obj变量和obj对象就在栈上。 遵循这么一个准则:指针变量和一般变量由上下文定义,指针所指向的内存在堆上,一般变量所指代的对象由上下文定义。 栈大小栈大小是有默认值的,如果申请的长期变量太大就会超过栈大小,造成栈溢出。 它的默认值是能够批改的,个别,在unix-like平台,栈的大小是由环境变量管制的,所以不能通过设置编译器(像gcc)的任何编译标记来设置;在windows平台,栈的大小是蕴含在可执行文件里的,它能够在visual c++的编译过程中设置,但在gcc里是不可行的。 办法为:我的项目->属性->链接器->零碎->堆栈保留大小 (字节数) 在个别状况下,不同平台默认栈大小如下所示(仅供参考) SunOS/Solaris 8172K bytes (Shared Version)Linux 10240K bytesWindows 1024K bytes (Release Version)AIX 65536K bytes 演示栈空间代码#include <iostream>class Test {public: Test() { std::cout << "Test" << std::endl; } ~Test() { std::cout << "~Test" << std::endl; }private: char a[1024 * 1024];};class TestContainer {public: TestContainer() { std::cout << "TestContainer" << std::endl; } ~TestContainer() { std::cout << "~TestContainer" << std::endl; }private: Test test;};int main(int argc, char* argv[]) { TestContainer t; while (1) {} return 0;}栈大小1MB(默认值),申请栈空间1MB后果:程序解体,stack overflow ...

September 25, 2023 · 1 min · jiezi

关于c:c语言基础

指令#define _CRT_SECURE_NO_WARNINGS //保障scanf函数可能失常运行#include <stdio.h> //函数printf应用#include <string.h> //函数strlen应用关键词getchar() while(1) char short int long long long float double scanfprintf extern const arr[](数组)strlen模板//编写代码的文件#include <stdio.h> //编译预处理指令//main函数是程序的入口//main函数有且只有一个int main() //定义主函数{ // 函数开始的标记 printf("hello world"); //输入所指定的一行信息 //避免程序闪退,咱们要观看运行后果 // getchar(); //获取一个字符,不输出就会始终期待 //或 // while(1); //通过死循环来卡住程序,避免闪退 return 0; //函数执行结束时返回函数值0} //函数完结的标记数据类型char //字符数据类型short //短整型int //整形long //长整形long long //更长的整形float //单精度浮点数double //双精度浮点数数据类型所占内存空间的大小{ printf("%d\n", sizeof(char); //1 printf("%d\n", sizeof(short); //2 printf("%d\n", sizeof(int); //4 printf("%d\n", sizeof(long); //4 printf("%d\n", sizeof(long long); //8 printf("%d\n", sizeof(float); //4 printf("%d\n", sizeof(double); //8 return 0; //完结}计算机中的单位bit(比特位)-->byte(字节)-->kb-->mb-->gb-->tb-->pb1byte = 8bit1kb = 1024byte1mb = 1024kb 1gb = 1024mb1tb = 1024gb1pb = 1024tb 类型的应用{ //类型 变量 = 数据 char = 'w'; int age = 20; return 0; //完结}全局变量和局部变量#include <stdio.h> //预处理指令int num = 10; //全局变量int main() //主函数{ int num = 10; //局部变量 printf("num=%d\n", num); //全局变量名与局部变量名雷同时,部分优先 return 0; //完结}全局变量 - {}内部定义的变量 ...

September 22, 2023 · 3 min · jiezi

关于c++:主机字节序和网络字节序的转换

古代CPU一次至多能装载4字节(32位机),即一个整数,这4个字节在内存中的排列程序将影响它的值。这就是字节序问题。字节序分为大端字节序(big endian)和小端字节序(little endian)。 如上图,大端字节序是指数据的高位存在内存的低地址处,小端字节序是指数据的高位存在内存的高地址处。 古代PC大多采纳小端字节序。当格式化的数据须要在两台应用不同字节序的主机进行传递时,接收端会谬误的解决。解决的办法是:发送端将发送的数据转换成大端字节序而后发送,接收端依据本人的字节序决定需不需要解决(小端转换,大端不解决)。 在做网络编程的时候,应用提供的库即可进行转换(linux库,windows下是一样的,头文件有所区别) #include <netinet/in.h>unsigned long int _htonl(unsigned long int hostlong);unsigned short int _htons(unsigned short int hostshort);unsigned long int _ntohl(unsigned long int netlong);unsigned short int _ntohs(unsigned short int netshort);如果平台没有提供这套,那么能够本人实现一下,原理很简略,就是调换下数据 #include <stdint.h>#define BigLittleSwap16(v) ((0xFF00 & (uint16_t)(v)) >> 8 | (0x00FF & (uint16_t)(v)) << 8)#define BigLittleSwap32(v) ((0xFF000000 & (uint32_t)(v)) >> 24 | (0x00FF0000 & (uint32_t)(v)) >> 8 | (0x0000FF00 & (uint32_t)(v)) << 8 | (0x000000FF & (uint32_t)(v)) << 24) #define BigLittleSwap64(v) ((0xFF00000000000000 & (uint64_t)(v)) >> 56 |(0x00FF000000000000 & (uint64_t)(v)) >> 40 |(0x0000FF0000000000 & (uint64_t)(v) )>> 24 |(0x000000FF00000000 & (uint64_t)(v)) >> 8 |(0x00000000FF000000 & (uint64_t)(v)) << 8| (0x0000000000FF0000 & (uint64_t)(v)) << 24 | (0x000000000000FF00 & (uint64_t)(v) )<< 40 | (0x00000000000000FF & (uint64_t)(v) )<< 56 )int isCPUBigEndian(){ union Data{ short val; char byte; } data; data.val = 0x0102; return (data.byte == 0x01);}unsigned long int _htonl(unsigned long int hostlong);unsigned short int _htons(unsigned short int hostshort);unsigned long int _ntohl(unsigned long int netlong);unsigned short int _ntohs(unsigned short int netshort);unsigned long int _htonl(unsigned long int hostlong){ return isCPUBigEndian() ? hostlong : BigLittleSwap32(hostlong);}unsigned short int _htons(unsigned short int hostshort){ return isCPUBigEndian() ? hostshort : BigLittleSwap16(hostshort);}unsigned long int _ntohl(unsigned long int netlong){ return isCPUBigEndian() ? netlong : BigLittleSwap32(netlong);}unsigned short int _ntohs(unsigned short int netshort){ return isCPUBigEndian() ? netshort : BigLittleSwap16(netshort);}测试: ...

September 21, 2023 · 2 min · jiezi

关于c:CH395Q学习笔记-一

一、TCP/IP简介TCP/IP协定层网络架构应用层:HTTP/FTP/MQTT/DNS/SMTP..传输层:TCP协定(基于连贯)、UDP协定(非连贯)网络层:IP协定、ARP协定(获取对方主机的MAC地址)、ICMP协定(ping)网际接口层:数据链路层、物理层 TCP/IP协定栈品种 二、CH395芯片CH395Q芯片通信骨架 CH395Q框架总体 CH395Q特点 CH395Q工作原理 CH395Q框图 CH395Q原理图解析

September 11, 2023 · 1 min · jiezi

关于c#:Unity-性能优化Shader分析处理函数ShaderUtilGetShaderGlobalKeywords用法

Unity 性能优化Shader剖析处理函数:ShaderUtil.GetShaderGlobalKeywords用法 点击封面跳转下载页面简介Unity 性能优化Shader剖析处理函数:ShaderUtil.GetShaderGlobalKeywords用法在Unity开发中,性能优化是一个十分重要的方面。一个常见的性能优化技巧是应用ShaderUtil.GetShaderGlobalKeywords函数来获取着色器的全局关键字。本文将介绍如何正确应用该函数,并提供一个实例代码来演示其用法。 什么是ShaderUtil.GetShaderGlobalKeywords函数?ShaderUtil.GetShaderGlobalKeywords是Unity引擎中的一个外部函数,它容许咱们获取一个着色器的全局关键字。全局关键字是在着色器中定义的一些开关,能够用来管制着色器的不同性能和成果。通过获取这些关键字,咱们能够在运行时动静地批改着色器的行为,从而实现更好的性能和成果。 如何应用ShaderUtil.GetShaderGlobalKeywords函数?因为ShaderUtil.GetShaderGlobalKeywords是一个internal标记的函数,咱们须要应用反射来调用它。上面是一个示例代码,展现了如何正确应用该函数: using System;using System.Reflection;using UnityEditor;using UnityEngine;public class ShaderUtilExample : MonoBehaviour{ private void Start() { // 获取以后激活的着色器 Shader shader = GetComponent<Renderer>().sharedMaterial.shader; // 应用反射调用GetShaderGlobalKeywords函数 MethodInfo getShaderGlobalKeywords = typeof(ShaderUtil).GetMethod("GetShaderGlobalKeywords", BindingFlags.Static | BindingFlags.NonPublic); string[] globalKeywords = (string[])getShaderGlobalKeywords.Invoke(null, new object[] { shader }); // 打印全局关键字 foreach (string keyword in globalKeywords) { Debug.Log(keyword); } }}在下面的示例代码中,咱们首先获取了以后激活的着色器。而后,咱们应用反射来调用GetShaderGlobalKeywords函数,并将以后着色器作为参数传递给它。函数返回一个蕴含全局关键字的字符串数组,咱们能够通过遍历数组来拜访每个关键字。 请留神,因为GetShaderGlobalKeywords是一个internal函数,它可能在将来的Unity版本中发生变化。因而,在应用该函数时,咱们须要小心解决,并确保在更新Unity版本时进行适当的测试和调整。 总结通过应用ShaderUtil.GetShaderGlobalKeywords函数,咱们能够获取着色器的全局关键字,从而实现更好的性能和成果。本文提供了一个应用反射调用该函数的示例代码,帮忙您了解如何正确应用它。在理论开发中,您能够依据本人的需要和场景,灵活运用这个函数来进行性能优化。 心愿本文对您在Unity性能优化方面有所帮忙!如果您有任何问题或疑难,请随时发问。 我的技术文章中可能存在的谬误向您示意诚挚的歉意。我致力确保提供精确牢靠的信息,但因为技术畛域的一直变动,谬误难以避免。如果您发现了谬误或有任何疑难,请与我分割。我将全力以赴纠正错误并提供更精确的信息。 再次向您示意最诚挚的歉意,我将更加审慎地审查和更新文章,以提供更好的浏览体验和精确的技术信息。 谢谢您的了解和反对。

September 11, 2023 · 1 min · jiezi

关于c++:C模拟实现简易vector容器模板类命名空间重载运算符

参考了这篇博客:C++实现vector 练习模板类,命名空间,重载运算符的根底应用。加了个命名空间和对方括号的重载,使得能够通过索引拜访数据。 #include <iostream>namespace Morpheus { template<typename T> class vector { private: T* _first; T* _last; T* _end; public: vector(int size = 5) { _first = new T[size]; _last = _first; _end = _first + size; } ~vector() { delete _first; _first = nullptr; _last = nullptr; _end = nullptr; } bool isEmpty() { return _first == _last; } bool isFull() { return _last == _end; } int size() { return _last - _first; } void push_back(const T& x) { if (isFull()) { expand(); } *_last++ = x; } void pop_back() { if (!isEmpty()) { _last--; } } T operator[](const int& i) { return _first[i]; } private: void expand() { int len = _end - _first; T* temp = new T[2 * len]; for (int i = 0; i < len; ++i) { temp[i] = _first[i]; } delete[] _first; _first = temp; _last = _first + len; _end = _first + 2 * len; } };}int main() { Morpheus::vector<double> v; v.push_back(1.2); v.push_back(1.3); v.push_back(1.4); for (int i = 0; i < v.size(); ++i) { std::cout << v[i] << ","; } v.pop_back(); v.pop_back(); for (int i = 0; i < v.size(); ++i) { std::cout << v[i] << ","; }}

September 10, 2023 · 1 min · jiezi

关于c#:C小白基础篇2-值类型字符串类型算数运算符赋值运算符关系运算符-等

 2.1 C#中的根本数据类型C#中变量的数据类型分为:值类型、援用类型、指针类型。 C#中值类型分为以下: 整型: byte、int 、short 、long byte的范畴 0-255 1字节 short的范畴 -32768 ---32767 2字节 int的范畴 -2147483648 -- 2147483647 4字节 long的范畴 -910^18 --- 910^18 8字节 浮点型: float -3.4x 10^38 ~ + 3.4 x 10^38 4个字节单精度 有精度损耗 0.0F 准确到小数点后大概7位 double (+/-)5.0 x 10-324 ~ (+/-)1.7 x 10308 8个字节双精度 有精度损耗 0.0D 准确到小数点后大概15~16位 十进制: decimal(准确) ±1.0 × 10^-28 到 ±7.9 × 10^28 16个字节 无损耗 0.0M 有效位数28位 布尔类型: bool (true、false) 字符类型: char 只能蕴含一个字符 ,‘\0’示意空字符 ...

September 10, 2023 · 2 min · jiezi

关于c:gdb调试c程序

本文由chatgpt生成应用 gdb 联合断点来分析程序是一种罕用的调试办法,容许您在程序执行的不同阶段进行执行并查看变量、堆栈和程序状态。以下是一些在应用 gdb 时联合断点进行剖析的根本步骤: 编译程序时启用调试信息: 在应用 gdb 进行调试之前,您须要确保在编译程序时启用了调试信息。通常,您能够应用 -g 标记来编译程序,例如: gcc -g -o my_program my_program.c启动 gdb: 在终端中运行 gdb 并指定要调试的可执行文件: gdb ./my_program设置断点: 应用 b 或 break 命令设置断点。例如,要在某个函数的结尾设置断点,能够执行: b function_name您还能够设置在特定行上的断点: b file_name.c:line_number运行程序: 应用 r 或 run 命令来运行程序: r当程序执行到断点时,它将进行并期待您的命令。 查看变量和状态: 在程序进行时,您能够应用 p 命令来查看变量的值,例如: p variable_name您还能够应用 bt 命令查看函数调用堆栈: bt单步执行: 应用 n 或 next 命令来单步执行程序,逐行执行代码。这将使您可能逐渐跟踪程序的执行。 n继续执行: 应用 c 或 continue 命令持续执行程序,直到遇到下一个断点或程序完结。 c删除断点: 应用 d 或 delete 命令来删除断点: d退出 gdb: 应用 q 或 quit 命令退出 gdb。 ...

September 9, 2023 · 1 min · jiezi

关于c++:喜马拉雅-Redis-与-Pika-缓存使用军规

作者:喜马拉雅 董道光 宣言:缓存不是万金油,更不是垃圾桶!!! 缓存作为喜马拉雅至关重要的根底组件之一,每天承载着微小的业务申请量。一旦缓存呈现故障,对业务的影响将十分重大。因而,确保缓存服务的稳固和高效运行始终是咱们的重要指标。 上面是咱们对喜马缓存历史故障复盘后总结的一套缓存应用标准,在此分享给大家,心愿小伙伴们能在缓存选型和应用的过程中少踩坑。 1. 缓存选型1.1 缓存类型介绍喜马线上缓存类型次要有 4 种: 1. redis 主从模式:官网原版 2.codis-redis:豌豆荚开源,redis 集群解决方案 3. 云数据库 redis:redis-cluster 容器化部署 4.xcache:基于 codis、pika、redis 自研的一套海量 KV 存储解决方案 1.2 缓存应用模式介绍应用模式次要分为 2 种: 1.cache 模式:数据不须要长久化,实例复原不须要加载数据,扩缩容不须要迁徙数据 2.store 模式:数据须要长久化,实例复原须要加载数据,扩缩容须要迁徙数据 上面是对各种类型缓存做了简略比照:   2. 缓存应用军规2.1 缓存类型应用标准1)redis 集群模式首选云数据库 redis,海量 KV 存储首选 xcache 云数据库 redis 采纳官网 redis cluster 模式,容器化部署,反对故障主动复原和弹性伸缩,是以后 redis 集群的主推计划,但不反对数据长久化,如果必须要做数据长久化,并且对延时要求十分高,能够应用 codis redis。数据量十分大,并且对延时要求不是特地高,能够抉择 xcache。 2) redis 不要当 db 应用 ,如果数据肯定要做长久化,能够抉择 xcache redis 当 db 应用,故障复原数据很慢,重大影响 SLA。并且如果主从全副挂掉,slave 机器无奈复原时,数据就会齐全失落。xcache 人造反对数据长久化 3) 不要应用客户端分片模式 客户端分片模式不具备高可用和弹性伸缩能力,倡议应用真正的集群模式,如 codis-redis、云数据库 redis、xcache ...

September 8, 2023 · 2 min · jiezi

关于c++:浅谈C命名空间的一些陷阱

前言最近看到个问题, 就是在命名空间中申明一个变量 ( int rand = 0 ), 用using namespace将这个命名空间引入 ( 净化 ) 进全局空间, 当函数调用此变量时产生谬误. 这是命名空间全局净化典型案例, 咱们进行一些分析 一、命名空间是什么?C++ 命名空间(namespace)是一种将全局作用域宰割为若干个小的作用域的机制。 它能够解决命名抵触(name clash)的问题,使不同作用域下的同名标识符互不烦扰。 命名空间的应用办法如下: 1.定义命名空间:能够在全局空间下定义命名空间,也能够在已有的命名空间内定义子命名空间,例如: namespace math{ int add(int a, int b) { return a + b; } namespace geometry { double circle_area(double r) { return 3.14159 * r * r; } } // namespace geometry} // namespace math2.应用命名空间:能够用 using namespace 或 using 关键字引入一个或多个命名空间,也能够应用作用域限定符拜访命名空间中的标识符。 using namespace math; // 引入 math 命名空间using math::geometry::circle_area; // 仅引入 math::geometry::circle_area 标识符int main(){ int sum = math::add(1, 2); // 应用作用域限定符拜访 math 命名空间中的函数 double area = circle_area(10.0); // 间接应用 circle_area 标识符(已引入) return 0;}二、命名空间全局净化命名空间是一种避免变量和函数因名称反复, 导致程序失败的机制。 ...

September 7, 2023 · 1 min · jiezi

关于c#:Unity-编辑器资源导入处理函数-OnPostprocessTexture-深入解析与实用案例

Unity 编辑器资源导入处理函数 OnPostprocessTexture 用法 点击封面跳转下载页面简介在Unity中,咱们能够应用编辑器资源导入处理函数(OnPostprocessTexture)来自定义解决纹理资源的导入过程。这个函数是继承自AssetPostprocessor类的,通过重写这个函数,咱们能够在纹理资源导入实现后执行一些自定义的操作。 继承 AssetPostprocessor首先,咱们须要创立一个继承自AssetPostprocessor的脚本。这个脚本将用于解决纹理资源的导入过程。以下是一个示例代码: using UnityEditor;using UnityEngine;public class TexturePostprocessor : AssetPostprocessor{ void OnPostprocessTexture(Texture2D texture) { // 在这里编写自定义的纹理导入解决逻辑 }}在这个示例中,咱们创立了一个名为TexturePostprocessor的脚本,并重写了OnPostprocessTexture函数。 自定义纹理导入解决逻辑在OnPostprocessTexture函数中,咱们能够编写自定义的纹理导入解决逻辑。以下是五个示例代码,展现了不同的用法: 1. 设置纹理的类型为Spritevoid OnPostprocessTexture(Texture2D texture){ TextureImporter textureImporter = (TextureImporter)assetImporter; textureImporter.textureType = TextureImporterType.Sprite;}在这个示例中,咱们将纹理的类型设置为Sprite。这样,在导入纹理时,它将被主动设置为Sprite类型。 2. 设置纹理的PackageTag namevoid OnPostprocessTexture(Texture2D texture){ TextureImporter textureImporter = (TextureImporter)assetImporter; textureImporter.spritePackingTag = "MyPackage";}在这个示例中,咱们将纹理的PackageTag name设置为"MyPackage"。这样,在导入纹理时,它将被主动增加到名为"MyPackage"的纹理包中。 3. 设置纹理的MipMaps勾选void OnPostprocessTexture(Texture2D texture){ TextureImporter textureImporter = (TextureImporter)assetImporter; textureImporter.mipmapEnabled = true;}在这个示例中,咱们将纹理的MipMaps勾选设置为true。这样,在导入纹理时,它将生成MipMaps,以提供更好的渲染性能和品质。 4. 批改纹理的导入格局void OnPostprocessTexture(Texture2D texture){ TextureImporter textureImporter = (TextureImporter)assetImporter; textureImporter.textureFormat = TextureImporterFormat.RGBA32;}在这个示例中,咱们将纹理的导入格局设置为RGBA32。这样,在导入纹理时,它将以RGBA32格局存储。 5. 批改纹理的导入平台设置void OnPostprocessTexture(Texture2D texture){ TextureImporter textureImporter = (TextureImporter)assetImporter; textureImporter.SetPlatformTextureSettings("Android", 2048, TextureImporterFormat.ETC2_RGBA8);}在这个示例中,咱们将纹理在Android平台上的导入设置批改为最大尺寸为2048,并且应用ETC2_RGBA8格局。这样,在导入纹理时,它将在Android平台上以指定的设置进行导入。 ...

September 6, 2023 · 2 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记p144p160

《Programming Abstractions In C》学习第56天,p144-p160。实现第三章内容学习,第三章总计54页(p107-p160),耗时10天,均匀6页/天。 一、技术总结第三章的内容次要介绍C语言中的库(library)和接口(interface),如咱们最常遇到的以下三种场景 随机数:<stdlib.h>字符串:<string.h>I/O操作:<stdio.h>二、英语总结1.subdivide和divide的区别是什么?答: (1)subdivide: vt. to divide sth into smaller parts; (2)divide: vt/ti. to seperate into parts。 p145, Because files are usually subdivided into individual lines, it is often usful to read an entire line of data at a time。依据上下文的意思,subdivide是分了再分(you divide it into smaller parts and then subdivide these parts into smaller parts)。 2.irrespective什么意思?答: (1)irrespective < respective: adv. without consideraing(不思考)。 (2)respective < respect:adj. relating each to each(各自的)。 ...

September 6, 2023 · 1 min · jiezi

关于c#:小白C基础篇1-变量赋值运算符常量号的作用占位符的使用

<1>变量:存储数据的容器。 变量的命名规定: 必须以 “字母” _ 或 @ 符号结尾,不要以数字结尾前面能够跟任意 “字母” 、数字、下划线留神: (1) 你起的变量名不要与C#零碎中的关键字反复(2) 在C#中,大小写是敏感的(3) 同一个作用域中变量名不容许反复定义(4) 定义变量时,变量名要有意义给变量起名字的时候要满足的命名标准: Camel 骆驼命名标准。要求变量名首单词的首字母要小写,其余每个单词的首字母要大写。多用于给变量命名。<2>赋值运算符 = int = 1;//变量能够反复赋值,一旦给一个变量赋了新值,那么变量中的老值就不复存在了<3>常量const 类型 常量名 = 常量值 const int PI = 3.14;<4>+号的作用 连贯:当+号两边有一边是字符串的时候,+号就起到连贯的作用。相加:两边是数字的时候<5>占位符的应用 int n1 = 10;int n2 = 20;int n3 = 30;Console.WriteLine("{1},{0},{2}", n1, n2,n3);Console.WriteLine("第一个数字是:" + n1 + ",第二个数字是:" + n2 + ",第三个数字是:" + n3);Console.WriteLine($"第一个数字是{n1},第二个数字是{n2},第三个数字是{n3}");

September 3, 2023 · 1 min · jiezi

关于c:C-语言-float-内存布局详解

前言C语言中的float并不像大多数人设想的那样, 因为计算机模仿的起因, 其本质是离散的而非间断的, 所以精度和范畴是肯定的, 这些都写在float.h头文件的宏中. 但通常, 咱们对教材的每一个字都意识, 连起来就读不懂了, 所以, 写下此博文, 详解之. 学过深刻了解计算机系统的同学, 都晓得float的实现形式, 依照IEEE规范, 由符号位, 阶码位, 尾数位组成, 本文给出一个代码, 打印float的符号位, 阶码位, 尾数位. 一、float中的宏定义这是float.h中无关float具体实现, 范畴, 精度等的宏常量, 根据64位零碎环境, 咱们一一解读. #include <float.h> FLT_RADIX; // 2; FLT_MANT_DIG; // 24; FLT_DIG; // 6; FLT_MIN_10_EXP; // (-37); FLT_MAX_10_EXP; // 38; FLT_EPSILON; // 1.19209290e-7F; FLT_MAX; // 3.40282347e+38F; FLT_MIN; // 1.17549435e-38F;FLT_RADIX 2This is the value of the base, or radix, of the exponent representation. This is guaranteed to be a constant expression, unlike the other macros described in this section. The value is 2 on all machines we know of except the IBM 360 and derivatives. ...

September 1, 2023 · 2 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记p139p143

《Programming Abstractions In C》学习第55天,p139-p140,总结如下: 一、技术总结1.文件I/O操作文件I/O操作能够分为一下这些步骤: (1)申明文件指针对象。 File *infile;(2)关上文件 fopen()。关上文件的模式有“r”, "w", "a"三种模式。 (3)传输数据 读取文件的形式能够是character by character( getc()/putc() ),也能够是line by line( fget()/fput() )。 (4)敞开文件 fclose()。 2.文件I/O操作示例:复制文件#include <stdio.h>#include <stdbool.h> // for bool, true, false data type#include <stdlib.h> // for exit()void CopyRemovingComments(FILE *infile, FILE *outfile);int main() { // 申明文件指针对象 FILE *infile, *outfile; char *infileName, *outfileName; /* * 关上文件:fopen() * 如果文件不存在,则返回NULL,所以须要查看 */ infileName = "D:\\CProject\\chater3.4\\jabber.txt"; // 这里应用的是绝对路径,也能够应用相对路径 outfileName = "D:\\CProject\\chater3.4\\jabbercopy.txt"; infile = fopen(infileName, "r"); if (infile == NULL) { printf("Cannot open input file: %s \n", infileName); exit(0); } /* * 传输数据 * 传输数据有很多种形式,例如chracter by character(getc/putc),line by line(fget/fput, ReadLine) * 为了解决stdio.h存在的一些问题,作者对stdio进行了封装,封装后失去的的是simpio */ outfile = fopen(outfileName, "w"); if (outfile == NULL) { printf("Cannot open output file: %s \n", outfileName); exit(0); } CopyRemovingComments(infile, outfile); /* * 敞开文件 */ fclose(infile); fclose(outfile); printf("Copying is completed"); return 0;}void CopyRemovingComments(FILE *infile, FILE *outfile) { int ch, nch; bool commentFlag; // 这里应用的是stdbool.h接口中的bool commentFlag = false; // 这里应用的是stdbool.h接口中的false,书中应用的是封装后的FALSE while ((ch = getc(infile)) != EOF) { if (commentFlag) { if (ch == '*') { nch = getc(infile); // if (nch == '/') { commentFlag = false; } else { ungetc(nch, infile); } } } else { if (ch == '/') { nch = getc(infile); if (nch == '*') { commentFlag = true; } else { ungetc(nch, infile); } } if (!commentFlag) { putc(ch, outfile); } } }}二、英语总结1.endpoint什么意思?答:c.the end of sth(起点)。 ...

August 31, 2023 · 2 min · jiezi

关于c++:C-sharedptr智能指针-reset-详解

C++ shared_ptr智能指针 reset() 详解最近看了个问题:智能指针援用计数为什么不是0?, 问将智能指针reset后为何不是援用减一. 看代码比拟好阐明 #include <cstdio>#include <memory>auto main() -> int{ std::shared_ptr<int> ptr = std::make_shared<int>(100); auto second = ptr; auto third = ptr; printf("num = %d, count = %ld\n", *ptr, ptr.use_count()); ptr.reset(); printf("ptr count = %ld\n", ptr.use_count()); printf("second and third count = %ld\n", second.use_count()); return 0;}ptr调用reset后, 援用数为0, 而不是2. 这是没有明确reset()函数的语义, 通过源码可能比拟好了解: void reset() _NOEXCEPT { shared_ptr().swap(*this); }这是reset()的实现, 用shared_ptr()调用结构一个长期指针, 并将其与调用reset()的指针对象(上例中的ptr)进行替换, 原对象指向的资源变为nullptr, 援用计数变为0. 长期对象指向原指针指向的资源(上例中的100), 援用计数变为3(长期对象, second, third), 语句完结, 长期对象析构, 援用计数减一. ...

August 30, 2023 · 1 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记p132p137

《Programming Abstractions In C》学习第53天,p132-p137,3.2大节“strings”总结如下: 一、技术总结3.2大节介绍了字符串的用法: 1.C语言是没有字符串(string)这种数据类型的,然而理论的场景中又很须要这种数据类型,那怎么示意字符串呢?有两种办法:1.用字符数组示意。2.用字符指针示意。 2.C自带的字符串库是string,作者为了更好的应用string,封装出了strlib库,所以在书中的代码常常会看到作者在头文件中引入strlib这个库,而不是间接援用string库。 3.执行字符串复制的时候要思考是否会产生buffer overflow问题。 二、英语总结1.rather什么意思?答:p132,“Note that this test does not check whether the strings are equal but rather whether the pointer are equal”。 rather在这里的意思是“adv. used to express an opposite opion”,用于表白一种相同的观点,具体的意思依据上下文。例如在这句话外面的意思是“而是”。 2.impose什么意思?答:in-(*en, "into, in") + pose("put, place"),vt. to introduce sth(引入),暗含“强制”之意。p132,Because the complexity imposed by string.h interface tends to get in the way of understanding more critical algorithmic issues,so...(因为string.h接口带来的复杂性往往会障碍了解更要害的算法问题,所以......)。 3.present什么意思?答:vt. to give, provide in a formal way。绝对于give或者provide而言,present更正式一些。p132,The interface is called strlib.h and is presented in its complete form in Figure 3-6。 ...

August 29, 2023 · 1 min · jiezi

关于c++:c-获取数字字符串字串

c++ 获取数字字符串的子串数值,比方给定字符串"123456",要获取第三位和第四位的数值,这里是34。 应用substr应用substr截取字串,再应用c_str()获取字符数组,再应用atoi()转换为数字 结构字符数组间接应用索引获取字符,构建字符数组,再应用atoi()转换为数字 代码#include <string>#include <iostream>#include <chrono>using namespace std;int main(int argc, char* argv[]) { string val = "123"; int total = 1000000; std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now(); for (int i = 0; i < total; i++) { int tmp = atoi(val.substr(1, 2).c_str()); } std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now(); std::chrono::microseconds diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start); cout << "using substr:" << diff.count() << "ms" << endl; start = std::chrono::system_clock::now(); for (int i = 0; i < total; i++) { char vals[2] = { val[1],val[2] }; int tmp = atoi(vals); } end = std::chrono::system_clock::now(); diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start); cout << "using char[]:" << diff.count() << "ms" << endl; return 0;}执行后果 ...

August 28, 2023 · 1 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记p130p131

《Programming Abstractions In C》学习第52天,p130-p131,总结如下: 一、技术总结1. pig latin game通过pig latin game把握字符复制,指针遍历等操作。 /* * 输出:字符串,这里采纳书中坐着自定义的getline函数 */#include <stdio.h>#include <string.h>#include "simpio.h"#define MaxWord 1000static _Bool IsVowel(char ch); // 书中p34, if实用于非此即彼的两种抉择(two-way);如果有多个,那么就应用switch。static void PigLatin(char *word, char buffer[], int bufferSize);static char *FindFirstVowel(char *word); // *示意函数FindFirstVowel返回一个指向char的指针int main() { char *word; char translationBuffer[MaxWord + 1]; printf("Enter a word: "); word = GetLine(); PigLatin(word, translationBuffer, MaxWord + 1); printf("Pig Latin: %s\n", translationBuffer);}/* * Function:IsVowel * Usage: isVowel = IsVowel(character) * ----------------------------------- * 该函数判断字符是否是元音字母,如果是,返回True,否则返回False。 */_Bool IsVowel(char ch) { switch (ch) { case 'A': case 'E': case 'I': case 'O': case 'U': case 'a': case 'e': case 'i': case 'o': case 'u': return TRUE; default: return FALSE; }}/* * Function: PigLatin * Usage: PigLatin(word, buffer, bufferSize); * ------------------------------------------ * This function translate a word from English to Pig Latin. The * translated word is written into the array buffer, which has an * allocated size of bufferSize. The code checks for buffer * overflow and generate an error if it occurs. */static void PigLatin(char *word, char buffer[], int bufferSize) { char *vp; int wordLength; vp = FindFirstVowel(word); wordLength = strlen(word); if (vp == word) { wordLength += 3; } else if (vp != NULL) { wordLength += 2; } if (wordLength >= bufferSize) { Error("Buffer overflow"); } if (vp == NULL) { // 单词中不存在元音字母:不做任何批改 strcpy(buffer, word); } else if (vp == word) { // 单词以元音字母结尾: 在单词开端增加way(示例:any > anyway) strcpy(buffer, word); strcat(buffer, "way"); } else { // 单词以辅音字母结尾: (1)将辅音字母挪动到单词尾部,直到第一个字母是元音字母。 // (2)挪动实现后,在单词尾部增加ay(示例:trash > ashtray) strcpy(buffer, vp); strncat(buffer, word, vp - word); strcat(buffer, "ay"); }}/* * FindFirstVowel: 找出单词中的第一个元音字母 */static char *FindFirstVowel(char *word) { char *cp; // 将原来的指针赋值给新的指针,防止原来的指针被批改 // 遍历指针 for (cp = word; *cp != '\0'; cp++) { // 留神:在这里*cp示意的是值 if (IsVowel(*cp)) { return cp; // 留神:cp++挪动之后,cp指向的地址扭转了 } } return NULL; // 如果找不到,则返回空指针(NULL)}残缺代码见:https://github.com/codists/Programming-Abstractions-In-C/tree/main/chapter3/piglatingame ...

August 28, 2023 · 2 min · jiezi

关于c#:C21天从入门到精通

download:C#21天从入门到精通C# 是一种古代的、通用的、面向对象的编程语言,它可能用来开发各种类型的应用程序,如桌面、Web、移动和游戏。要学习 C#,你需要了解它的基本语法、数据类型、控制流、方法、类和接口等概念。你还需要安装一个集成开发环境(IDE),如 Visual Studio 或 Visual Studio Code,来编写和运行你的代码。 为了帮助你入门 C#,我为你筹备了一篇示例代码文章,它将向你展示如何创建一个简略的 C# 控制台应用程序,它可能输入一句问候语,并接受用户输出的名字。这个程序将涉及以下内容: 使用 using 指令来引用命名空间使用 namespace 关键字来定义命名空间使用 class 关键字来定义类使用 static 关键字来定义动态成员使用 void 关键字来定义无返回值的方法使用 string 类型来示意文本数据使用 Console.WriteLine() 方法来输入文本到控制台使用 Console.ReadLine() 方法来从控制台读取文本使用 + 运算符来连接字符串使用 $ 字符来创建插值字符串上面是示例代码文章的内容: // C# 入门示例代码文章 // 本文将向你展示如何创建一个简略的 C# 控制台应用程序,它可能输入一句问候语,并接受用户输出的名字。 // 首先,咱们需要使用 using 指令来引用 System 命名空间,它蕴含了许多罕用的类和方法,如 Console 类。using System; // 而后,咱们需要使用 namespace 关键字来定义一个命名空间,它是一种组织代码的形式,可能避免命名冲突。// 咱们可能给命名空间起任意的名字,这里咱们使用 HelloWorld 作为示例。namespace HelloWorld{ // 接下来,咱们需要使用 class 关键字来定义一个类,它是一种封装数据和行为的对象。// 咱们可能给类起任意的名字,这里咱们使用 Program 作为示例。class Program{ // 而后,咱们需要使用 static 关键字来定义一个动态方法,它是一种不需要创建对象就可能间接调用的方法。 // 咱们可能给方法起任意的名字,这里咱们使用 Main 作为示例。 // Main 方法是一个非凡的方法,它是程序的入口点,也就是程序开始执行的地方。 // Main 方法必须有一个 void 类型的返回值,示意它不返回任何数据。 // Main 方法也必须有一个 string 类型的数组参数,示意它可能接受一些命令行参数。 static void Main(string[] args) { // 接下来,咱们可能在 Main 方法中编写咱们想要执行的代码。 // 首先,咱们使用 Console.WriteLine() 方法来输入一句问候语到控制台。 // Console.WriteLine() 方法可能接受一个 string 类型的参数,示意要输入的文本。 // 咱们可能间接使用双引号括起来的文本作为参数,也可能使用变量或表达式作为参数。 Console.WriteLine("Hello, world!"); // 而后,咱们使用 Console.WriteLine() 方法再次输入一句提醒语到控制台。 // 这次咱们使用了一个换行符 \n 来示意换行,这样可能让输入更好看。 Console.WriteLine("Please enter your name:\n"); // 接着,咱们使用 Console.ReadLine() 方法来从控制台读取用户输出的文本,并赋值给一个 string 类型的变量 name。 // Console.ReadLine() 方法没有参数,它会一直等待用户输出,直到用户按下回车键为止。 // 咱们可能给变量起任意的名字,这里咱们使用 name 作为示例。 string name = Console.ReadLine(); // 最初,咱们使用 Console.WriteLine() 方法再次输入一句问候语到控制台,这次咱们使用了用户输出的名字来定制问候语。 // 为了连接字符串,咱们可能使用 + 运算符,也可能使用 $ 字符来创建插值字符串,它可能让咱们在字符串中间接使用变量或表达式。 // 咱们使用了一个逗号和一个空格来分隔问候语和名字,这样可能让输入更天然。 Console.WriteLine("Hello, " + name + "!"); // 使用 + 运算符 Console.WriteLine($"Hello, {name}!"); // 使用插值字符串 // 这样,咱们就实现了一个简略的 C# 控制台应用程序,它可能输入一句问候语,并接受用户输出的名字。 // 咱们可能在 Visual Studio 或 Visual Studio Code 中运行和调试咱们的代码,看看成果如何。 }}}复制我心愿这篇示例代码文章对你有所帮助。如果你想要学习更多对于 C# 的内容,你可能参考以下的资源: ...

August 27, 2023 · 1 min · jiezi

关于c++:c-判断基类指针指向的真实对象类型

在 c++ 面向对象应用中,咱们经常会定义一个基类类型的指针,在运行过程中,这个指针可能指向一个基类类型的对象,也可能指向的是其子类类型的对象,那当初问题来了,咱们如何去判断这个指针到底执行了一个什么类型的对象呢?明天咱们就聊一下这个问题,首先咱们要辨别是否容许 RTTI,据此有不同方法。 1 容许应用 RTTI在关上 rtti 的场景下,能够应用 dynamic_cast 和 typeid 这两个运算符来判断对象的实在类型。 1.1 应用 dynamic_castdynamic_cast 用于在运行时进行多态类型检查和转换,它能够将指向基类的指针转换为指向派生类的指针或援用。如果转换胜利,则阐明对象属于指标类或其派生类。如果转换失败,则返回空指针。咱们看如下例子,咱们想判断指针 basePtr 是否指向了 Child2 类型的对象。总共进行了两次测试,第一次让该指针指向了 Child1 类型的对象,第二次则是指向了 Child2 类型的对象。 #include <iostream>class Basic {public: virtual void say() { std::cout << "我是基类" << std::endl; }};class Child1 : public Basic {public: void say() { std::cout << "我是 child 1" << std::endl; }};class Child2 : public Basic {public: void say() { std::cout << "我是 child 2" << std::endl; }};int main(){ Basic* basePtr; basePtr = new Child1(); if (dynamic_cast<Child2*>(basePtr)) { std::cout << "[test 1]指针指向了 Child2 类型对象" << std::endl; } else { std::cout << "[test 1]指针没有指向 Child2 类型对象" << std::endl; } delete basePtr; basePtr = new Child2(); if (dynamic_cast<Child2*>(basePtr)) { std::cout << "[test 2]指针指向了 Child2 类型对象" << std::endl; } else { std::cout << "[test 2]指针没有指向 Child2 类型对象" << std::endl; } delete basePtr;}让咱们一起看看两次的打印,这是合乎咱们的预期的,应用 dynamic_cast 能够判断一个基类类型的指针是否指向了某个具体类类型。 ...

August 27, 2023 · 2 min · jiezi

关于c++:c初始

介绍C++ 是一种高级语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的。C++ 进一步裁减和欠缺了 C 语言,是一种面向对象的程序设计语言。C++ 可运行于多种平台上,如 Windows、MAC 操作系统以及 UNIX 的各种版本。 本教程通过通俗易懂的语言来解说 C++ 编程语言。 环境设置我采纳的是 gcc + vscode的搭配形式进行开发 正文为什么须要正文呢?正文是为了更好的解释,同时也将进步源代码的可读性。C++ 正文个别有两种: // - 个别用于单行正文。/ ... / - 个别用于多行正文。例子如下: #include <iostream>using namespace std; int main() { // 这是一个正文 cout << "Hello World!"; return 0;}C++ 正文以 / 开始,以 / 终止。例如: #include <iostream>using namespace std; int main() { /* 这是正文 */ /* C++ 正文也能够 * 跨行 */ cout << "Hello World!"; return 0;}也能够在多行正文中嵌套单行正文 ...

August 26, 2023 · 1 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记p127p129

《Programming Abstractions In C》学习第51天,p127-p129,总结如下: 一、技术总结1. string library把握罕用函数如strlen,strcpy用法。 2.buffer overflow(缓冲区溢出)(1)什么是buffer? p129,Arrays that are preallocated and later use as a repository for data called buffers。 (2)什么是缓冲区溢出? p129,Writing data past the end of an buffer is a common programming error called buffer overflow。 //buffer overflow示例char *src = "Hello";char dst[1]; // dst称为bufferstrcpy(dst, src); // 该操作会导致buffer overflow问题书中只是做一个简略的阐明,具体可参考: (1) wikipedia, Buffer overflow: https://en.wikipedia.org/wiki/Buffer_overflow 二、英语总结1.“The function will go ahead and copy characters right on past the end of the buffer.”语法分析答:这里的应该是The function will go ahead and (copy characters right) (on past the end of the buffer),这句话有几个要留神的中央: ...

August 24, 2023 · 1 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记p123p126

《Programming Abstractions In C》学习第50天,p123-p126,总结如下: 一、技术总结1.notaion这也是一个在计算机相关书籍中呈现的词,但有时却不是那么好了解,因为它能够指代很多对象,这里做一个记录。示例:p124。 In C, you can use any character array to hold string data. char str[6] = {'h', ' ', 'l', ' ', 'o', '\0'};or, more compactly, char str[6] = "hello";If you use array notation, the standar idion for processing every character in a string looks like this: for (int i = 0; str[i] != '\0'; i++) { printf("i=%d\n", str1[i]);}在这里,“notation”以了解为“the activity of representing sth by a special system of marks or character”,即“notation”示意的是一种“标记办法”、“示意办法”。 ...

August 21, 2023 · 2 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记-p118p122

《Programming Abstractions In C》学习第49天,p118-p122,总结如下: 一、技术总结1.随机数(1)seed p119,"The initial value--the value that is used to get the entire process start--is call a seed for the random generator." 二、数学总结1.均匀分布(uniform distribution)均匀分布属于概率论和统计学领域,有连续性均匀分布和离散型均匀分布。 参考:(1)连续性均匀分布(continuous uniform distribution):(2)离散型均匀分布(discrte uniform distribution): 三、英语总结1.discern是什么意思?答:dis-("off, away") + cernere("distinguish, seperate, shif"),"to see, recorgnize, understand sth that is not clear(辨认)",当应用这个单词的时候,示意“被辨认”的对象并不是那么“clear”。 2.against什么意思?p120,“Finally, every implementation needs to include its own interface so the compiler can check the prototypes against the actual definitions.”。这里之所以要把against抽出来说,是因为against很多中央会用到,但要说间接翻译成什么词,却不是那么好间接给出答案,这里做一个总结。against总体的意思是“prep. opposite/toward”。 3.suffice什么意思?答:i. to be enough。形容词是“sufficent”。p120,“The comments in the interface should suffice.”(接口中定义的正文应该足够了)。 ...

August 20, 2023 · 1 min · jiezi

关于c:Programming-abstractions-in-C阅读笔记-p114p117

《Programming Abstractions in C》学习第48天,p114-p117,总结如下: 一、技术总结次要通过random number介绍了随机数的相干用法,interface示例(random.h),client program示例(craps.c)。 #include <stdio.h>#include "genlib.h"#include "random.h"static bool TryToMakePoint(int point);static int RollTwoDice(void);void main() { int point; Randomize(); // 定义在自定义的random.h文件中 printf("This program plays a game of craps.\n"); point = RollTwoDice(); switch (point) { case 7: case 11: printf("That's a natural. You win.\n"); break; case 2: case 3: case 12: printf("That's craps. You lose.\n"); break; default: printf("Your point is %d.\n", point); if (TryToMakePoint(point)) { printf("You made your point. You win.\n"); } else { printf("You rolled a seven. You lose.\n"); } }}static bool TryToMakePoint(int point) { int total; while (TRUE) { total = RollTwoDice(); if (total == point) return TRUE; if (total == 7) return FALSE; }}static int RollTwoDice(void) { int d1, d2, total; printf("Rolling the dice ...\n"); d1 = RandomInteger(1, 6); // 定义在自定义的random.h文件中 d2 = RandomInteger(1, 6); total = d1 + d2; printf("You rolled %d and %d -- that's %d.\n", d1, d2, total); return total;}二、英语总结1.inclusive什么意思?答:adj. including a particular thing。当探讨波及到范畴时,咱们常常会说在某两个数之间,如果蕴含这两个数,那么就用inclusive这个词来形容这两个数。示例:p114,The first prototype is for the function RandomInteger(low, high), which return a randomly chosen integer in the range between low and high, inclusive。 ...

August 16, 2023 · 1 min · jiezi

关于c++:c-error-crosses-initialization-of-问题探究

最近在写代码的时候,碰到了 crosses initialization of ... 的问题,只因我在 switch 的某个 case 分支下定义了一个变量,于是乎便将这个问题整顿一下。 1 switch case 的某个分支下定义了变量switch case 是咱们在工作中常见的分支语句,如果在某个分支下不失当的应用了局部变量,就有可能呈现本文提到的问题。 1.1 问题代码示例#include <iostream>void switchTest(int code);int main() { switchTest(1);}void switchTest(int code) { switch (code) { case 1: int myNum = 0; break; case 2: break; default: break; }}上述代码,我在第一个 case 分支下定义了 myNum 变量,尝试编译,呈现如下谬误。次要看 C2360 这一行,myNum 的初始化操作由 case标签跳过,也就是说当 code !=1 的时候,不会进行 myNum 的初始化。第一反馈是“我这个 myNum 只在 case 1 下用啊,不初始化就不初始化嘛,反正其余中央又不必”。 呃,这就牵扯到变量的作用范畴了。myNum 这个局部变量的作用范畴是从定义处开始直到 switch 语句完结。艰深说,就算咱们跳过了 case 1 处的初始化,myNum 在前面的分支中,也是能够被拜访到的,被拜访到就有可能被应用(尽管咱们本人没打算在前面应用,但编译器认为这是有危险的),然而咱们又没有对其进行初始化,那这就会出问题。那这个问题怎么解决呢? ...

August 16, 2023 · 2 min · jiezi

关于c#:Winform-窗体缩放下-使用剪切板功能会出现页面闪动

问题Winform窗体,在首次应用剪切板性能时会呈现页面闪动。 起因应用了PresentionCore.dll里的Clipboard导致的,具体起因未知 解决应用其余办法进行剪切板性能,比方WindowAPI,Forms的Clipboard 演示代码MyClipboard.cs using System;using System.Runtime.InteropServices;namespace WindowsFormsApp2{ class MyClipboard { [DllImport("User32")] public static extern bool OpenClipboard(IntPtr hWndNewOwner); [DllImport("User32")] public static extern bool CloseClipboard(); [DllImport("User32")] public static extern bool EmptyClipboard(); [DllImport("User32")] public static extern bool IsClipboardFormatAvailable(int format); [DllImport("User32")] public static extern IntPtr GetClipboardData(int uFormat); [DllImport("User32", CharSet = CharSet.Unicode)] public static extern IntPtr SetClipboardData(int uFormat, IntPtr hMem); public static void FormsCopy() { System.Windows.Forms.Clipboard.SetDataObject("Forms"); } public static void PresentationCoreCopy() { System.Windows.Clipboard.SetDataObject("PresentationCore"); } public static void Win32Copy() { if (!OpenClipboard(IntPtr.Zero)) { return; } EmptyClipboard(); SetClipboardData(13, Marshal.StringToHGlobalUni("Win32")); CloseClipboard(); } }}Form1.cs ...

August 15, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的Mask遮罩组件的介绍及使用

Unity UGUI的Mask(遮罩)组件的介绍及应用1. 什么是Mask组件?Mask(遮罩)组件是Unity UGUI中的一个重要组件,用于限度子对象的可见区域。通过设置遮罩组件,能够实现一些特殊效果,如显示局部图片、裁剪文本等。 2. Mask组件的工作原理Mask组件通过将子对象与遮罩对象进行比拟,只显示与遮罩对象重叠的局部,从而实现遮罩成果。遮罩对象能够是任意形态的UI元素,如Image、RawImage等。 3. Mask组件的罕用属性Show Mask Graphic:是否显示遮罩对象的图形。Mask Interaction:遮罩对象的交互方式,可抉择None、Visible Inside Mask和Visible Outside Mask。Alpha Cutoff:遮罩对象的透明度阈值,用于管制遮罩的显示范畴。4. Mask组件的罕用函数IsRaycastLocationValid:判断指定地位是否在遮罩范畴内。GetModifiedMaterial:获取通过遮罩解决后的材质。5. 示例代码示例1:显示局部图片using UnityEngine;using UnityEngine.UI;public class ImageMaskExample : MonoBehaviour{ public Image mask; public RawImage image; void Start() { mask.sprite = Resources.Load<Sprite>("MaskImage"); image.texture = Resources.Load<Texture>("Image"); image.transform.SetParent(mask.transform); mask.GetComponent<Mask>().showMaskGraphic = false; }}操作步骤: 创立一个Image对象作为遮罩对象,设置其形态为圆形。创立一个RawImage对象作为子对象,设置其图片为须要显示的图片。将遮罩对象和子对象增加到Canvas中。将子对象的父对象设置为遮罩对象。设置Mask组件的Show Mask Graphic属性为false。示例2:裁剪文本using UnityEngine;using UnityEngine.UI;public class TextMaskExample : MonoBehaviour{ public Text mask; public Text text; void Start() { mask.text = "Mask Text"; text.text = "Hello World"; text.transform.SetParent(mask.transform); mask.GetComponent<Mask>().showMaskGraphic = false; }}操作步骤: ...

July 10, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的GridLayoutGroup网格布局组件的介绍及使用

Unity UGUI的GridLayoutGroup(网格布局)组件的介绍及应用1. 什么是GridLayoutGroup组件?GridLayoutGroup是Unity UGUI中的一种布局组件,用于在UI界面中创立网格布局。它能够依据指定的行数、列数和间距主动排列子物体,使它们依照网格的模式排列。 2. GridLayoutGroup的工作原理GridLayoutGroup组件会依据指定的行数和列数,将子物体依照从左到右、从上到下的顺序排列。它还能够设置间距,管制子物体之间的距离。当子物体的数量超过网格的容量时,GridLayoutGroup会主动创立新的行或列来包容多余的子物体。 3. GridLayoutGroup的罕用属性Cell Size:指定每个单元格的大小。Spacing:指定子物体之间的间距。Start Corner:指定网格的起始角落。Start Axis:指定网格的起始轴线。Constraint:指定网格的束缚形式,能够是按行束缚或按列束缚。Constraint Count:指定每行或每列的最大子物体数量。4. GridLayoutGroup的罕用函数CalculateLayoutInputHorizontal():计算程度方向上的布局。CalculateLayoutInputVertical():计算垂直方向上的布局。SetLayoutHorizontal():设置程度方向上的布局。SetLayoutVertical():设置垂直方向上的布局。5. 示例代码示例1:创立一个2x2的网格布局using UnityEngine;using UnityEngine.UI;public class GridLayoutExample : MonoBehaviour{ public GridLayoutGroup gridLayout; public GameObject prefab; void Start() { gridLayout.constraint = GridLayoutGroup.Constraint.FixedColumnCount; gridLayout.constraintCount = 2; for (int i = 0; i < 4; i++) { Instantiate(prefab, transform); } }}操作步骤: 创立一个空的GameObject,并将GridLayoutExample脚本挂载下来。在Inspector面板中,将GridLayoutGroup组件拖拽到gridLayout变量上。创立一个预制体,将其拖拽到prefab变量上。运行游戏,能够看到预制体依照2x2的网格布局排列。注意事项: 须要提前创立好预制体,并将其拖拽到prefab变量上。示例2:创立一个3x3的网格布局,并设置间距using UnityEngine;using UnityEngine.UI;public class GridLayoutExample : MonoBehaviour{ public GridLayoutGroup gridLayout; public GameObject prefab; void Start() { gridLayout.constraint = GridLayoutGroup.Constraint.FixedColumnCount; gridLayout.constraintCount = 3; gridLayout.spacing = new Vector2(10, 10); for (int i = 0; i < 9; i++) { Instantiate(prefab, transform); } }}操作步骤: ...

July 10, 2023 · 2 min · jiezi

关于c#:Unity-UGUI的Canvas画布组件的介绍及使用

Unity UGUI的Canvas(画布)组件的介绍及应用1. 什么是Canvas组件?Canvas(画布)是Unity UGUI零碎中的一个重要组件,用于在屏幕上绘制UI元素。它是UI元素的容器,能够蕴含各种UI元素,如按钮、文本、图像等。Canvas组件提供了一种不便的形式来治理和渲染UI元素。 2. Canvas组件的工作原理Canvas组件通过渲染器将UI元素绘制到屏幕上。它应用层级构造来治理UI元素的显示程序,能够通过设置UI元素的层级来管制它们的显示程序。Canvas组件还能够设置渲染模式,包含屏幕空间、世界空间和摄像机空间等。 3. Canvas组件的罕用属性Render Mode(渲染模式):设置Canvas的渲染模式,包含屏幕空间、世界空间和摄像机空间等。Sorting Layer(排序层级):设置Canvas的排序层级,用于管制UI元素的显示程序。Order in Layer(层级程序):设置UI元素在排序层级中的显示程序。Pixel Perfect(像素完满):启用像素完满模式,能够确保UI元素在不同分辨率下的显示成果统一。Reference Pixels Per Unit(参考像素单位):设置参考像素单位,用于计算UI元素的大小和地位。4. Canvas组件的罕用函数SetRenderMode(RenderMode mode):设置Canvas的渲染模式。SetSortingLayerName(string name):设置Canvas的排序层级名称。SetOrderInLayer(int order):设置UI元素在排序层级中的显示程序。SetPixelPerfect(bool pixelPerfect):设置是否启用像素完满模式。SetReferencePixelsPerUnit(float pixelsPerUnit):设置参考像素单位。5. 示例代码示例1:创立一个屏幕空间的Canvasusing UnityEngine;using UnityEngine.UI;public class CanvasExample : MonoBehaviour{ void Start() { // 创立一个屏幕空间的Canvas GameObject canvasObject = new GameObject("Canvas"); Canvas canvas = canvasObject.AddComponent<Canvas>(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; // 创立一个UI元素 GameObject textObject = new GameObject("Text"); textObject.transform.SetParent(canvas.transform); Text text = textObject.AddComponent<Text>(); text.text = "Hello World!"; }}操作步骤: 创立一个空的GameObject,并将脚本挂载到该GameObject上。在Start函数中,创立一个屏幕空间的Canvas。创立一个UI元素,并将其设置为Canvas的子物体。设置UI元素的文本内容为"Hello World!"。示例2:创立一个世界空间的Canvasusing UnityEngine;using UnityEngine.UI;public class CanvasExample : MonoBehaviour{ void Start() { // 创立一个世界空间的Canvas GameObject canvasObject = new GameObject("Canvas"); Canvas canvas = canvasObject.AddComponent<Canvas>(); canvas.renderMode = RenderMode.WorldSpace; // 创立一个UI元素 GameObject textObject = new GameObject("Text"); textObject.transform.SetParent(canvas.transform); Text text = textObject.AddComponent<Text>(); text.text = "Hello World!"; }}操作步骤: ...

July 10, 2023 · 2 min · jiezi

关于c#:Unity-UGUI的ScrollRect滚动视图组件的介绍及使用

Unity UGUI的ScrollRect(滚动视图)组件的介绍及应用1. 什么是ScrollRect组件?ScrollRect(滚动视图)是Unity UGUI中的一个罕用组件,用于在UI界面中创立可滚动的区域。通过ScrollRect组件,能够实现在无限的空间内显示大量的内容,并且能够通过滑动手势来浏览内容。 2. ScrollRect组件的工作原理ScrollRect组件通过将内容搁置在一个可滚动的矩形区域内,而后通过拖动或滑动手势来扭转内容的显示地位。ScrollRect组件蕴含一个Viewport(视口)和一个Content(内容)两个子对象,Viewport用于限度Content的显示范畴,而Content则蕴含了理论的内容。 3. ScrollRect组件的罕用属性Content:用于搁置理论的内容的RectTransform对象。Horizontal:是否容许程度方向的滚动。Vertical:是否容许垂直方向的滚动。Movement Type:滚动的类型,可选的类型有:Unrestricted(不受限制)、Elastic(弹性)、Clamped(限度)。Inertia:是否启用惯性滚动。Deceleration Rate:惯性滚动的加速率。Scroll Sensitivity:滚动的灵敏度。4. ScrollRect组件的罕用函数ScrollTo:滚动到指定地位。StopMovement:进行滚动。OnBeginDrag:开始拖拽时调用的函数。OnDrag:拖拽过程中调用的函数。OnEndDrag:完结拖拽时调用的函数。5. 示例代码示例1:根本的滚动视图using UnityEngine;using UnityEngine.UI;public class ScrollRectExample : MonoBehaviour{ public ScrollRect scrollRect; void Start() { // 设置Content的大小 RectTransform content = scrollRect.content; content.sizeDelta = new Vector2(0, 1000); // 设置滚动视图的滚动范畴 scrollRect.verticalNormalizedPosition = 1; }}操作步骤: 创立一个空的GameObject,并增加ScrollRect组件。在Hierarchy面板中选中ScrollRect对象,将Content对象拖拽到ScrollRect的Content属性中。将示例代码增加到ScrollRectExample脚本中,并将ScrollRect对象拖拽到scrollRect属性中。运行游戏,能够看到滚动视图中的内容能够通过滑动手势进行滚动。示例2:限度滚动范畴using UnityEngine;using UnityEngine.UI;public class ScrollRectExample : MonoBehaviour{ public ScrollRect scrollRect; void Start() { // 设置Content的大小 RectTransform content = scrollRect.content; content.sizeDelta = new Vector2(0, 1000); // 设置滚动视图的滚动范畴 scrollRect.verticalNormalizedPosition = 1; scrollRect.movementType = ScrollRect.MovementType.Clamped; }}操作步骤: ...

July 10, 2023 · 1 min · jiezi

关于c++:书籍推荐零基础的Modern-C入门第二版

书籍:Modern C++ for Absolute Beginners作者:Slobodan Dmitrović出版:Apress入群邀请:7个业余方向交换群+1个材料需要群原文:书籍下载-《零根底的Modern C++入门》-第二版 01 书籍介绍以结构化、扼要且敌对的形式学习C++编程语言。本书传授古代C++编程语言的基础知识、C++规范库以及包含C++23在内的古代C++规范,无需任何编程教训。 C++是一门独特的语言,它的复杂性令人诧异,但在许多方面却十分优雅和晦涩。然而,它也是一门不能仅凭猜想就能学会的语言,容易犯错且难以正确使用。为了解决这个问题,每个章节都充斥了逐步减少复杂度的实在示例。《零根底的Modern C++入门》,第二版不仅传授C++23的编程技巧,更提供了打牢C++根底的内容。 作者率领你学习C++编程语言、规范库以及从C++11到C++23的根底。每章配有适量的理论知识和大量的源代码示例。你将应用C++23的性能和规范,并对之前的C++版本进行比拟和钻研。 浏览本书后,你将可能开始应用古代C++规范进行编程。为此,书中还附有大量相干的源代码示例,能够通过专门的GitHub存储库收费获取。 02 通过这本书,能够学习到什么· 以敌对而无效的形式介绍古代C++编程· 学习C++的基础知识:类型、运算符、变量、常量、表达式、援用、函数、类、输出/输入、智能指针、多态等· 在Windows上设置Visual Studio环境,在Linux上应用GCC编写本人的代码· 申明和定义函数、类和对象,并将代码组织到命名空间中· 摸索面向对象编程:类和对象、封装、继承、多态等,应用最先进的C++个性· 利用最佳实际来组织源代码和管制程序流程· 相熟C++语言的要点和注意事项等内容· 把握lambda表达式、继承、多态、智能指针、模板、模块、契约、概念等基础知识 03 作者简介Slobodan Dmitrović是一位软件参谋、培训师,也是几本编程书籍的作者。他是一名资深的研发软件开发人员,在该行业积攒了二十年的教训。Slobodan为企业客户和学术机构提供C++培训课程。 04 书籍纲要 1. SCI写作书籍举荐:《Science Research Writing》-second Edition 书籍举荐-《基于C++的数字图像处理》-2023书籍举荐-《ROS2机器人编程扼要教程》

July 10, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的Dropdown下拉菜单组件的介绍及使用

Unity UGUI的Dropdown(下拉菜单)组件的介绍及应用1. 什么是Dropdown组件?Dropdown(下拉菜单)是Unity UGUI中的一个罕用组件,用于在用户点击或抉择时显示一个下拉菜单,提供多个选项供用户抉择。 2. Dropdown组件的工作原理Dropdown组件由两局部组成:一个可点击的按钮和一个下拉菜单。当用户点击按钮时,下拉菜单会开展,显示所有选项。用户能够通过点击选项来进行抉择。 3. Dropdown组件的罕用属性Options:下拉菜单中的选项列表。Caption Text:按钮上显示的文本。Template:下拉菜单的模板。Item Text:下拉菜单中选项的文本。On Value Changed:当抉择的值发生变化时触发的事件。4. Dropdown组件的罕用函数ClearOptions():清空下拉菜单中的选项。AddOptions(List<string> options):向下拉菜单中增加选项。SetValueWithoutNotify(int value):设置以后抉择的值,但不触发事件。5. 示例代码示例1:创立一个简略的下拉菜单using UnityEngine;using UnityEngine.UI;public class DropdownExample : MonoBehaviour{ public Dropdown dropdown; void Start() { dropdown.ClearOptions(); dropdown.AddOptions(new List<string> { "Option 1", "Option 2", "Option 3" }); }}操作步骤: 创立一个空物体,并将Dropdown组件增加到该物体上。将DropdownExample脚本增加到该物体上。在Inspector面板中,将Dropdown组件的援用拖拽到DropdownExample脚本的dropdown字段上。运行游戏,下拉菜单中将显示"Option 1"、"Option 2"和"Option 3"三个选项。注意事项: 在Start函数中增加选项,确保在游戏开始时下拉菜单曾经初始化。示例2:获取以后抉择的值using UnityEngine;using UnityEngine.UI;public class DropdownExample : MonoBehaviour{ public Dropdown dropdown; void Start() { dropdown.ClearOptions(); dropdown.AddOptions(new List<string> { "Option 1", "Option 2", "Option 3" }); } public void OnDropdownValueChanged(int value) { Debug.Log("Selected option: " + dropdown.options[value].text); }}操作步骤: ...

July 10, 2023 · 1 min · jiezi

关于c++:C如何用简单的汇编指令实现C复杂抽象的面向对象概念6动态内存newdelete

动态内存调配是在堆上调配的,且本人调配的,必须要本人开释,否则就会内存透露,具体C++怎么实现的呢? 老规矩,先上C++验证代码: #include<iostream>// #include <cstdlib>/** * 内存治理:堆区内存调配*/int main(){ int *arr = new int[11]; arr[0] = 0; arr[9] = 9; arr[88] = 88;// 越界 // std::cout<<arr[88] << std::endl; delete[] arr; int* arr_malloc = (int*)malloc(11 * sizeof(int)); arr_malloc[0] = 0; arr_malloc[9] = 9; arr_malloc[88] = 88;// 越界 free(arr_malloc); return 0;}下面C++代码,别离用new/delete调配开释堆内存,又用malloc/free调配开释内存,且还进行了越界赋值,看看什么成果。,上面是对应的汇编: main:.LFB1522: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp# new/delete movl $44, %edi # 申请调配44个字节 call _Znam@PLT movq %rax, -16(%rbp) # rax里是函数返回值,rbp-8存储这块堆内存的地址 movq -16(%rbp), %rax movl $0, (%rax) # 堆内存+0的地址赋值为0,即第0个元素 movq -16(%rbp), %rax addq $36, %rax movl $9, (%rax) # # 9 * 4 == 36,即第9个元素 movq -16(%rbp), %rax addq $352, %rax # 88 * 4 = 352 movl $88, (%rax) # 越界赋值88 cmpq $0, -16(%rbp) # 空指针查看, 如果相等,那么零标记(ZF)将被设置为1,否则将被设置为0。 je .L2 # je .L2指令查看零标记,如果它为1,则跳转到.L2标签处 movq -16(%rbp), %rax movq %rax, %rdi call _ZdaPv@PLT# malloc/free.L2: movl $44, %edi call malloc@PLT # malloc调配44字节 movq %rax, -8(%rbp) movq -8(%rbp), %rax movl $0, (%rax) movq -8(%rbp), %rax addq $36, %rax movl $9, (%rax) movq -8(%rbp), %rax addq $352, %rax # 越界赋值 movl $88, (%rax) movq -8(%rbp), %rax movq %rax, %rdi call free@PLT # 不做空指针查看,间接调用free去开释 movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc根据上述汇编可知,汇编上间接调用的是零碎调用的动态链接库,具体new/delete、malloc/free的实现代码,须要本人看内核源码,回头钻研钻研。然而基本上咱们能够宏观晓得,C++编译器只管调用零碎调用,去给你调配开释内存,而且必须是你本人执行delete/free了之后,它才会取调用对应的零碎调用去开释对应的堆内存,如果你C++代码里不执行delete/free,那么C++编译器也不会帮你查看。 ...

July 9, 2023 · 1 min · jiezi

关于c++:重学C04-说透C右值引用上

文章首发【重学C++】04 | 说透C++右值援用(上) 引言大家好,我是只讲技术干货的会玩code,明天是【重学C++】的第四讲,在后面《03 | 手撸C++智能指针实战教程》中,咱们或多或少接触了右值援用和挪动的一些用法。 右值援用是 C++11 规范中一个很重要的个性。第一次接触时,可能会很乱,不分明它们的目标是什么或者它们解决了什么问题。接下来两节课,咱们具体讲讲右值援用及其相干利用。内容很干,留神珍藏! 左值 vs 右值简略来说,左值是指能够应用&符号获取到内存地址的表达式,个别呈现在赋值语句的右边,比方变量、数组元素和指针等。 int i = 42;i = 43; // ok, i是一个左值int* p = &i; // ok, i是一个左值,能够通过&符号获取内存地址int& lfoo() { // 返回了一个援用,所以lfoo()返回值是一个左值 int a = 1; return a; };lfoo() = 42; // ok, lfoo() 是一个左值int* p1 = &lfoo(); // ok, lfoo()是一个左值相同,右值是指无奈获取到内存地址的表白是,个别呈现在赋值语句的左边。常见的有字面值常量、表达式后果、长期对象等。 int rfoo() { // 返回了一个int类型的长期对象,所以rfoo()返回值是一个右值 return 5;};int j = 0;j = 42; // ok, 42是一个右值j = rfoo(); // ok, rfoo()是右值int* p2 = &rfoo(); // error, rfoo()是右值,无奈获取内存地址左值援用 vs 右值援用C++中的援用是一种别名,能够通过一个变量名拜访另一个变量的值。 ...

July 9, 2023 · 3 min · jiezi

关于c++:C如何用简单的汇编指令实现C复杂抽象的面向对象概念3重载与重写

简略重述下重载与重写的区别:重载。类的成员函数的函数名雷同,但参数列表不同(类型、个数、程序不同),就是函数的重载。C++编译器依据你调用函数时传入的不同的参数列表,去执行对应的那个函数。这点在c语言中是不能实现的,因为C语言没有这个语法个性,所以C编译器不反对,如果你这么写编译器必定会给你报错无奈编译通过。重写。即笼罩,子类的某个成员函数A的返回值、函数名和参数列表和父类某个成员函数A截然不同,那么子类就把父类的A函数给笼罩掉了,当前调用子类的A函数,执行的是子类A函数的逻辑,如果在子类中不重写,则将会调用父类的A函数。重载简略剖析下,我猜想,重载在汇编中也没什么不同,必定和一般函数一个样,有不同的函数标号,执行哪个重载函数,编译器就会Call 哪个函数。C++编译器会将每个成员函数都别离翻译成汇编并给它起个标号名,依据你要调用哪个具体的重载函数,去Call哪个汇编标号的函数。上面来剖析下: #include<iostream>/** * 继承:重载*/class Son{public: int a; void add(){ a = 0; } void add(int i){ a = i; } void add(int i, int j){ a = i+j; }};int main(){ Son son; son.add(); son.add(33); son.add(10, 78); return 0;}类中有3个重载函数add,函数名一样,参数不一样,别离调用,看看编译成汇编是怎么实现重载个性的: main:.LFB1525: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp # 调配16字节栈帧给main函数 movq %fs:40, %rax movq %rax, -8(%rbp) xorl %eax, %eax leaq -12(%rbp), %rax # 算出rbp-12这个值 movq %rax, %rdi call _ZN3Son3addEv # 调用add() leaq -12(%rbp), %rax movl $33, %esi movq %rax, %rdi call _ZN3Son3addEi # 调用add(int i) leaq -12(%rbp), %rax movl $78, %edx movl $10, %esi movq %rax, %rdi call _ZN3Son3addEii # 调用add(int i, int j) movl $0, %eax movq -8(%rbp), %rcx xorq %fs:40, %rcx je .L6 call __stack_chk_fail@PLT.L6: leave .cfi_def_cfa 7, 8 ret .cfi_endproc果然不出咱们所料,即便简单的重载概念,也只是编译器层面的抽象概念,真正体现到硬件、cpu指令、内存调配与读写时,其实仍旧是C语言汇编那点事件,无非就是内存在哪调配,它的地址怎么计算,而后传参,Call函数标号。通过这里,能够更加粗浅领会到,所谓C++的语法个性在汇编层面的实现,其实就是C语言汇编的各种组合,包含内存调配、地址计算、变量的字节长度计算、函数调用、参数传递等等。 ...

July 8, 2023 · 2 min · jiezi

关于c:重学C02-脱离指针陷阱深入浅出-C-智能指针

文章首发【重学C++】02 脱离指针陷阱:深入浅出 C++ 智能指针 前言大家好,明天是【重学C++】系列的第二讲,咱们来聊聊C++的智能指针。 为什么须要智能指针在上一讲《01 C++如何进行内存资源管理》中,提到了对于堆上的内存资源,须要咱们手动调配和开释。治理这些资源是个技术活,一不小心,就会导致内存透露。 咱们再给两段代码,切身体验下原生指针治理内存的噩梦。 void foo(int n) { int* ptr = new int(42); ... if (n > 5) { return; } ... delete ptr;}void other_fn(int* ptr) { ...};void bar() { int* ptr = new int(42); other_fn(ptr); // ptr == ?}在foo函数中,如果入参n > 5, 则会导致指针ptr的内存未被正确开释,从而导致内存透露。 在bar函数中,咱们将指针ptr传递给了另外一个函数other_fn,咱们无奈确定other_fn有没有开释ptr内存,如果被开释了,那ptr将成为一个悬空指针,bar在后续还持续拜访它,会引发未定义行为,可能导致程序解体。 下面因为原生指针使用不当导致的内存透露、悬空指针问题都能够通过智能指针来轻松防止。 C++智能指针是一种用于治理动静分配内存的指针类。基于RAII设计理念,通过封装原生指针实现的。能够在资源(原生指针对应的对象)生命周期完结时主动开释内存。 C++规范库中,提供了两种最常见的智能指针类型,别离是std::unique_ptr 和 std::shared_ptr。接下来咱们别离具体开展介绍。 吃独食的unique_ptrstd::unique_ptr 是 C++11 引入的智能指针,用于治理动态分配的内存。每个 std::unique_ptr 实例都领有对其所蕴含对象的惟一所有权,并在其生命周期完结时主动开释对象。 创立unique_ptr对象咱们能够std::unique_ptr的构造函数或std::make_unique函数(C++14反对)来创立一个unique_ptr对象,在超出作用域时,会主动开释所治理的对象内存。示例代码如下: #include <memory>#include <iostream>class MyClass {public: MyClass() { std::cout << "MyClass constructed" << std::endl; } ~MyClass() { std::cout << "MyClass destroyed" << std::endl; }};int main() { std::unique_ptr<MyClass> ptr1(new MyClass); // C++14开始反对std::make_unique std::unique_ptr<int> ptr2 = std::make_unique<int>(10); return 0;}代码输入: ...

July 8, 2023 · 3 min · jiezi

关于c#:Unity-UGUI的Scrollbar滚动条组件的介绍及使用

Unity UGUI的Scrollbar(滚动条)组件的介绍及应用一、什么是Scrollbar组件?Scrollbar组件是Unity中UGUI零碎提供的一种UI组件,次要用于在UI界面中提供滚动条性能,使用户能够通过滚动条来查看超出屏幕范畴的内容。 二、Scrollbar组件是如何工作的?Scrollbar组件的工作原理次要是通过扭转滚动条的地位来扭转关联的内容的显示地位。当用户拖动滚动条时,Scrollbar组件会依据滚动条的地位计算出一个值(范畴在0到1之间),而后将这个值传递给关联的内容,由内容依据这个值来扭转本人的显示地位。 三、Scrollbar组件的罕用属性Scrollbar组件的罕用属性次要有以下几个: Direction:滚动条的方向,能够是从左到右、从右到左、从下到上、从上到下。Value:滚动条的以后值,范畴在0到1之间。Size:滚动条滑块的大小,范畴在0到1之间,值越大,滑块越大。NumberOfSteps:滚动条的步进值,如果设置为0,则滚动条能够平滑滚动;如果设置为大于0的值,则滚动条会依照步进值来滚动。四、Scrollbar组件的罕用函数Scrollbar组件的罕用函数次要有以下几个: OnValueChanged:当滚动条的值扭转时触发的事件。Rebuild:从新构建滚动条。LayoutComplete:当滚动条的布局实现时触发的事件。GraphicUpdateComplete:当滚动条的图形更新实现时触发的事件。五、Scrollbar组件的应用示例上面将通过5个示例来介绍如何应用Scrollbar组件。 示例1:创立一个简略的Scrollbar// 创立一个ScrollbarScrollbar scrollbar = new GameObject("Scrollbar").AddComponent<Scrollbar>();// 设置滚动条的方向scrollbar.direction = Scrollbar.Direction.LeftToRight;// 设置滚动条的值scrollbar.value = 0.5f;// 设置滚动条滑块的大小scrollbar.size = 0.1f;示例2:监听Scrollbar的值扭转事件// 创立一个ScrollbarScrollbar scrollbar = new GameObject("Scrollbar").AddComponent<Scrollbar>();// 增加值扭转事件的监听scrollbar.onValueChanged.AddListener((value) => { Debug.Log("Scrollbar value changed: " + value);});示例3:设置Scrollbar的步进值// 创立一个ScrollbarScrollbar scrollbar = new GameObject("Scrollbar").AddComponent<Scrollbar>();// 设置滚动条的步进值scrollbar.numberOfSteps = 10;示例4:从新构建Scrollbar// 创立一个ScrollbarScrollbar scrollbar = new GameObject("Scrollbar").AddComponent<Scrollbar>();// 从新构建滚动条scrollbar.Rebuild(CanvasUpdate.Prelayout);示例5:监听Scrollbar的布局实现事件和图形更新实现事件// 创立一个ScrollbarScrollbar scrollbar = new GameObject("Scrollbar").AddComponent<Scrollbar>();// 增加布局实现事件的监听scrollbar.onValueChanged.AddListener(() => { Debug.Log("Scrollbar layout complete.");});// 增加图形更新实现事件的监听scrollbar.onValueChanged.AddListener(() => { Debug.Log("Scrollbar graphic update complete.");});六、注意事项在应用Scrollbar组件时,须要留神以下几点: Scrollbar组件的值范畴是0到1,不要设置超出这个范畴的值。如果要使Scrollbar能够平滑滚动,须要将步进值设置为0。在监听Scrollbar的值扭转事件时,须要留神不要在事件处理函数中再次批改Scrollbar的值,否则可能会导致有限循环。七、参考资料Unity官网文档:ScrollbarUnity官网教程:UGUI Scrollbar

July 8, 2023 · 1 min · jiezi

关于c++:C如何用简单的汇编指令实现C复杂抽象的面向对象概念2简单继承

简略的继承C++编译器是怎么把逻辑上是继承关系的C++代码,父类和子类,怎么用汇编体现这种关系呢?老规矩,先上C++代码: #include<iostream>/** * 简略继承*/class Father{public: int a; Father(){ a = 11; } ~Father(){ a = 22; }protected: int b;private: int c;};class Son : public Father{public: int s; Son(){ s = 66; }};int main(){ Son son; son.a = 888; return 0;}汇编是如何体现的呢? .file "3-object-class-inherit-0.cpp" .text .section .rodata .type _ZStL19piecewise_construct, @object .size _ZStL19piecewise_construct, 1_ZStL19piecewise_construct: .zero 1 .local _ZStL8__ioinit .comm _ZStL8__ioinit,1,1 .section .text._ZN6FatherC2Ev,"axG",@progbits,_ZN6FatherC5Ev,comdat .align 2 .weak _ZN6FatherC2Ev .type _ZN6FatherC2Ev, @function_ZN6FatherC2Ev:.LFB1523: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq %rdi, -8(%rbp) # 把main函数的rbp-48这个值,放到 rbp-8 movq -8(%rbp), %rax # 把main函数的rbp-48这个值,放到rax寄存器 movl $11, (%rax) # 把11放到main函数的rbp-48这个值所指向的内存处(弄了半天,绕这么大弯子,就是想让父类构造函数的赋值语句,赋值到main函数栈帧所指向的内存,因为编译器无奈间接算出父类成员变量a的内存地址,所以只能用传值的形式一路传过来) nop popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE1523: .size _ZN6FatherC2Ev, .-_ZN6FatherC2Ev .weak _ZN6FatherC1Ev .set _ZN6FatherC1Ev,_ZN6FatherC2Ev .section .text._ZN6FatherD2Ev,"axG",@progbits,_ZN6FatherD5Ev,comdat .align 2 .weak _ZN6FatherD2Ev .type _ZN6FatherD2Ev, @function_ZN6FatherD2Ev:.LFB1526: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq %rdi, -8(%rbp) movq -8(%rbp), %rax movl $22, (%rax) # 把22放到main函数栈帧rbp-48这个值,这是变量a的内存地址,放到a所在的内存地址处。留神(%rax)是指rax寄存器外面的数值所指向的内存,而%rax是指寄存器 nop popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE1526: .size _ZN6FatherD2Ev, .-_ZN6FatherD2Ev .weak _ZN6FatherD1Ev .set _ZN6FatherD1Ev,_ZN6FatherD2Ev .section .text._ZN3SonC2Ev,"axG",@progbits,_ZN3SonC5Ev,comdat .align 2 .weak _ZN3SonC2Ev .type _ZN3SonC2Ev, @function_ZN3SonC2Ev:.LFB1529: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp # 给Son子类的构造函数分配内存 movq %rdi, -8(%rbp) # 把main函数的rbp-48这个值放到Son构造函数的rbp-8内存里 movq -8(%rbp), %rax # 把main函数的rbp-48这个值放到rax movq %rax, %rdi # 把main函数的rbp-48这个值放到rdi寄存器用作传参数,在子构造函数里调用父构造函数,能够看出,是先调用的父构造函数的逻辑,再执行子构造函数的代码逻辑 call _ZN6FatherC2Ev # 调用父构造函数 movq -8(%rbp), %rax movl $66, 12(%rax) # 执行子构造函数的代码逻辑 rax+12 == rbp-48+12 == rbp-36 nop leave .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE1529: .size _ZN3SonC2Ev, .-_ZN3SonC2Ev .weak _ZN3SonC1Ev .set _ZN3SonC1Ev,_ZN3SonC2Ev .section .text._ZN3SonD2Ev,"axG",@progbits,_ZN3SonD5Ev,comdat .align 2 .weak _ZN3SonD2Ev .type _ZN3SonD2Ev, @function_ZN3SonD2Ev:.LFB1533: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp # 调配栈桢 movq %rdi, -8(%rbp) # # 把main函数栈帧rbp-48这个值,这是变量a的内存地址,放到rbp-8内存处 movq -8(%rbp), %rax movq %rax, %rdi # 计算main函数栈帧rbp-48这个值,这是变量a的内存地址,父类析构函数用到它 call _ZN6FatherD2Ev nop leave .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE1533: .size _ZN3SonD2Ev, .-_ZN3SonD2Ev .weak _ZN3SonD1Ev .set _ZN3SonD1Ev,_ZN3SonD2Ev .text .globl main .type main, @functionmain:.LFB1531: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 pushq %rbx subq $40, %rsp # 为main调配40字节栈帧 .cfi_offset 3, -24 movq %fs:40, %rax movq %rax, -24(%rbp) xorl %eax, %eax leaq -48(%rbp), %rax # 这不是超出栈了吗? movq %rax, %rdi # 把rbp-48这个值传到结构函数参数?(这里构造函数是无参结构啊)留神:无参结构只是C++语法个性上的说法,汇编里,用到什么数据就传什么数据,具体用到什么,编译器本人计算 call _ZN3SonC1Ev movl $888, -48(%rbp) # 父类的成员变量是在main函数的栈帧里调配的,该对象是main函数的局部变量,所以在栈上调配,如果是全局变量,就不在栈上调配了 movl $0, %ebx leaq -48(%rbp), %rax # 计算main函数栈帧rbp-48这个值,这是变量a的内存地址,是为了一路传给父类析构函数用的 movq %rax, %rdi # call _ZN3SonD1Ev # 析构函数 movl %ebx, %eax movq -24(%rbp), %rdx xorq %fs:40, %rdx je .L7 call __stack_chk_fail@PLT.L7: addq $40, %rsp popq %rbx popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE1531: .size main, .-main .type _Z41__static_initialization_and_destruction_0ii, @function_Z41__static_initialization_and_destruction_0ii:.LFB2015: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movl %edi, -4(%rbp) movl %esi, -8(%rbp) cmpl $1, -4(%rbp) jne .L10 cmpl $65535, -8(%rbp) jne .L10 leaq _ZStL8__ioinit(%rip), %rdi call _ZNSt8ios_base4InitC1Ev@PLT leaq __dso_handle(%rip), %rdx leaq _ZStL8__ioinit(%rip), %rsi movq _ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax movq %rax, %rdi call __cxa_atexit@PLT.L10: nop leave .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE2015: .size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii .type _GLOBAL__sub_I_main, @function上述汇编,我删掉了一点点开端的非核心汇编,避免篇幅太长。 ...

July 8, 2023 · 3 min · jiezi

关于c++:C如何用简单的汇编指令实现C复杂抽象的面向对象概念1绪论

绪论之前,我花了几章工夫,摸索了C语言编译器,如何用简略的汇编指令,实现C语言面向过程的概念,包含实现根本数据类型、构造体、逻辑管制分支构造、函数调用、参数传递和指针等,根本对用汇编实现面向过程有了大略的把握和宏观上的理解,而我做这件事的最终目标,就是想摸索C++的面向对象,是如何用汇编实现的。 「这也是我最喜爱的学习形式,一开始不陷入细枝末节,先从宏观上把握整体构造、整体框架,再去宏观把握、宏观细扣具体的知识点,与大家共勉。」 在写C++面向对象的汇编实现原理之前,我想先思考思考我想要问的问题是什么?想要摸索的是哪些点?因而在这篇文章里记录、思考一下! 次要有以下相干知识点须要摸索钻研: # 纯C++语法的使用,编译器提供了语法个性1. 创立1个类,类中蕴含根本数据类型、根本成员函数、结构与析构函数,main函数里创立个对象进行对其进行操作;2. 父子类继承时,父类不同修饰符下的数据、成员函数是如何解决的?3. 重载与重写是如何实现的?4. 多态相干?5. 虚函数与纯虚函数?6. 类的动态成员,友元函数等7. 抽象类、运算符重载等# 库的调用:8. 多线程,开启一个新的线程,会被编译成什么汇编?9.volatile/原子变量/锁...会被编译成什么汇编?临时想到这些想理解的,其它的边写边想吧!能把C++面向对象的实现原理齐全搞清楚,也须要花点功夫。正好上半年也刚过去,下半年的打算也要逐步开始,那么就先心愿8月31日前能利用业余时间把C++大部分面向对象的问题都摸索分明!

July 8, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的Toggle复选框组件的介绍及使用

Unity UGUI的Toggle(复选框)组件的介绍及应用1. 什么是Toggle组件?Toggle(复选框)是Unity UGUI中的一个罕用组件,用于实现复选框的性能。它能够被选中或勾销选中,并且能够代码通过其制控状态。 2. Toggle组件的工作原理组Toggle件由两个局部组成:背景记标和。景背用于显示复选框的外观示意于用记标,复选框的选中状态。当被件组Toggle点击时,它会主动切换选中状态,并触发相应的事件。 3. Toggle组件的罕用属性Is On示意:Toggle组件的当选状态代码通过能够,管制。Transition:示意组Toggle件的过渡成果,包含None、Color Tint、Sprite Swap等选项。Graphic:示意Toggle组件的背景图像。GroupToggle示意:件组所属Toggle的Group组。On Value Changed:示意Toggle组件选中状态扭转时触发的事件。 ## 4. Toggle组件的罕用函数 void Toggle():切换组Toggle的件选中状态。void OnClickPointer(PointerEventData eventData):解决Toggle组件的点击事件。5. 示例代码1 示例 创立一个简略的Toggle组件创立一个对象Canvas,并在Canvas下创立Toggle一个对象。设置组件Toggle的Is On属性为true。运行游戏,点击Toggle组件,察看Toggle组件的选中状态是否扭转。示例2:应用代码管制Toggle组件选的中状态创立一个Canvas对象在,并Canvas下创立一个Toggle对象。在脚本中获取Toggle组件的援用。在代码中应用Toggle组件的Is On属性管制Toggle组件的选中状态。using UnityEngine;using UnityEngine.UI;public class ToggleExample : MonoBehaviour{ public Toggle toggle; private void Start() { toggle =.isOn true; }}示例3:应用Toggle组件的事件创立一个Canvas对象,并在下Canvas创立Toggle一个对象。在脚本中增加一个办法,用于解决Toggle组件的选中状态扭转事件。将该办法绑定到Toggle组件的On Value Changed事件上。using UnityEngine;using UnityEngine.UI;public class ToggleExample : MonoBehaviour{ public Toggle toggle; private void Start() { toggle.onValueChanged.AddListener(OnToggleValueChanged); } private void OnToggleValueChanged(bool isOn) { Debug.Log("Toggle is " + (isOn ? "on" : "off")); }}示例4:应用Toggle组件的过渡成果创立一个Canvas对象,并在Canvas下创立一个Toggle对象。设置Toggle组件的Transition属性为Colorint T。设置Toggle组件的Graphic属性为一个背景图像。运行游戏,察看Toggle组件的过渡成果。示例5:应用Toggle组件的Toggle Group创立一个Canvas对象,并在Canvas下创立两Toggle个对象。创立一个ToggleGroup对象,并将两个Toggle对象的Group属性为设置该ToggleGroup对象。运行游戏,察看Toggle组件的选中状态是否互斥。注意事项Toggle组件必放须在Canvas对象下能力失常显示。Toggle组件的选中状态能够通过代码管制也,能够通过点击切换。Toggle组件的选状态中扭转时会触发相应的事件。参考资料Unity官网文档:Toggle

July 8, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的Slider滑动条件组的介绍及使用

Unity UGUI的Slider(滑动条)件组的介绍及应用1. 什么是Slider组件?Slider(滑动条)是Unity UGUI中的一种罕用UI组件用,于在用户界面中实现滑动抉择的性能。通过拖动滑块,用户能够抉择一个数值范畴的内值。 2. Slider组件的工作原理Slider组件由两局部组成:滑动区域和滑块。滑动区域用于显示滑动条的背景,而滑块则示意以后的数值地位。用户能够通过拖动滑块来扭转数值。 3. Slider组件的罕用属性Min Value(最小值):滑动的条值小最 **。Max Value最(大)值:滑动条的最值大。Value(以后值):滑动条的以后值。Whole Numbers(只容许整值数整抉择许允只是否:)数。Direction(方向):滑动条的方向,能够是程度或垂直。Handle Slide Area(滑块)域区动滑:滑块能够在滑动区域内滑动。Handle Slide Range(滑块滑动范畴):滑块在动滑区域内滑的动范畴。4. Slider组常的件用函数SetValueWithoutNotify(float value):设置滑动条的以后值,但不触发OnValueChanged事件。OnValueChanged(UnityAction<float> action):当滑动条的值发生变化时触发的事件。5. 示例代码示例1:根本应用using UnityEngine;using UnityEngine.UI;public class SliderExample : MonoBehaviour{ public Slider slider; private void Start() { slider.onValueChanged.AddListener(OnSliderValueChanged); } private void OnSliderValueChanged(float value) { Debug.Log("Slider value changed: " + value); }}操作步骤: 创立一个空物体,并将Slider组件增加到该物体上2。. 将SliderExample脚本增加到该物体上。在Inspector面板中,将SliderExample脚本的slider字段关联到Slider组件。运行游戏,拖动滑块,察看控制台输入。注意事项: 通过监听Slider的onValueChanged事件,能够在滑动条的值发生变化时执行自定义的逻辑。示例2:限度数值范畴using UnityEngine;using UnityEngine.UI;public class SliderExample : MonoBehaviour { public Slider slider; private void Start() { slider.minValue = 0; slider.maxValue = 100; slider.wholeNumbers = true; }}操作步骤: ...

July 8, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的InputField输入框组件的介绍及使用

UGUI的InputField(输入框)组件的介绍及应用1. 什么是UGUI的InputField组件?UGUI的InputField组件是Unity中的一个用户界面组件,用于接管用户的输出。它能够用于创立文本输入框、明码输入框等性能。 2. UGUI的InputField组件的工作原理UGUI的InputField组件通过监听用户的输出事件,用户将输出的内容保留在一个字符串中,并将该字符串显示在输入框中。用户能够通过键盘输入、鼠标点击等形式进行输出。 .3 UGUI的Input组Field件的罕用属性text: 输入框中显示的文本内容。placeholder: 输入框中未输出内容时显示的占位符文本。characterLimit: 输入框中可输出的最大数字符限度。 -contentType: 输入框中可输出的内容类型,如整数、小数、明码等。onValueChanged: 输入框内容扭转时触发的事件。4. UGUI的InputField组件的函数用常- ActivateInputField(): 激活输入框,使其能够接管用户输出。 DeactivateInputField(): 勾销激活输入框,使其无奈接管用户输出。OnSubmit(): 用户按下回车键或点击提交按钮时触发的事件。5. 示例代码示例1:创立一个简略的文本输入框using UnityEngine;using UnityEngine.UI;public class Example : MonoBehaviour{ public InputField inputField; private void Start() { inputField.onValueChanged.AddListener(OnInputValueChanged); } private void OnInputValueChanged(string value) { Debug.Log("输入框内容扭转:" + value); }}操作步骤: 创立一个空物体,并将脚本Example挂载到该物体上。在场景中创立一个InputField对象,并将其拖拽到Example脚本的inputField字段中。运行游戏,输入框中输出内容,察看控制台输入。事留神项: 示例代码中的OnInputValueChanged办法会在输入框内容扭转时被调用。示例2:限度输入框中的字符数using UnityEngine;using UnityEngine.UI;public class Example : MonoBehaviour{ public InputField inputField; public int maxCharacterLimit = 10; private void Start() { inputField.characterLimit = maxCharacterLimit; }}操作步骤:1. 创立一个空物体,并将脚本Example挂载到物该体上。 在场景中创立一个InputField对象,并将其拖拽到Example脚本的inputField字段中。将maxCharacterLimit的值设置为想要限度的最大字符数。运行游戏,输入框中输出超过最大字符数的内容,察看输入框中的字符数是否受限制。注意事项: ...

July 8, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的Image图片组件的介绍及使用

UGUI的Image(图片)组件的介绍及应用1. 什么是UGUI的Image(图片)组件?UGUI的Image(图片)组件是Unity引擎中的一种UI组件,用于显示2D图像。它提供了一种简略而灵便的形式来在游戏中加载和显示图片。 2. 为什么要应用UGUI的Image(图片)组件?应用UGUI的Image组件能够不便地在游戏中展现各种图片资源,比方角色头像、道具图标等。它具备以下长处: 易用性:UGUI的Image组件提供了简略易懂的接口,使得开发者能够轻松地加载和显示图片。灵活性:能够通过设置Image组件的属性,如色彩、透明度等,来实现各种成果的图片展现。性能优化:UGUI的Image组件反对图片的批量渲染,可能高效地解决大量的图片资源。3. 如何应用UGUI的Image(图片)组件?上面是应用UGUI的Image组件的五个具体例子代码,并附带操作步骤和注意事项: 示例代码1:加载并显示图片using UnityEngine;using UnityEngine.UI;public class ImageExample : MonoBehaviour{ public Image image; public Sprite sprite; private void Start() { image.sprite = sprite; }}操作步骤: 创立一个空对象,并将该脚本挂载到该对象上。在场景中增加一个Canvas对象,并将Canvas的Render Mode设置为Screen Space - Overlay。在Canvas下创立一个Image对象,并将Image组件拖拽到脚本的image字段上。将要显示的图片资源拖拽到脚本的sprite字段上。运行游戏,图片将会在场景中显示进去。注意事项: 确保图片资源曾经导入到Unity工程中。确保Canvas的Render Mode正确设置,以保障图片在正确的地位显示。示例代码2:设置图片的色彩using UnityEngine;using UnityEngine.UI;public class ImageExample : MonoBehaviour{ public Image image; private void Start() { image.color = Color.red; }}操作步骤: 创立一个空对象,并将该脚本挂载到该对象上。在场景中增加一个Canvas对象,并将Canvas的Render Mode设置为Screen Space - Overlay。在Canvas下创立一个Image对象,并将Image组件拖拽到脚本的image字段上。运行游戏,图片的色彩将会变为红色。注意事项: 能够通过设置image.color属性来扭转图片的色彩。色彩值能够应用Unity的Color构造体来示意。示例代码3:设置图片的透明度using UnityEngine;using UnityEngine.UI;public class ImageExample : MonoBehaviour{ public Image image; private void Start() { Color color = image.color; color.a = 0.5f; image.color = color; }}操作步骤: ...

July 8, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的Text文本组件的介绍及使用

UGUI的Text(文本)组件的介绍及应用什么是UGUI的Text(文本)组件?UGUI(Unity Graphic User Interface)是Unity引擎的一套用户界面零碎,而Text(文本)组件是UGUI中用于在游戏界面中显示文本的组件。该组件能够用于显示游戏中的文字、数字、标签等信息。 为什么要应用UGUI的Text(文本)组件?应用UGUI的Text组件能够在游戏界面中实时显示文字信息,不便玩家理解游戏的状态、交互信息等。 应用UGUI的Text(文本)组件的步骤:在Unity编辑器中创立一个Canvas对象,并为Canvas增加一个Text组件。 重点步骤: 在Hierarchy面板中右键点击Canvas对象,抉择“UI -> Text”创立一个Text子对象。设置Text组件的款式属性。 重点步骤: 在Inspector面板中抉择Text组件,设置其地位、大小、字体、字号、色彩等款式属性。通过脚本管制Text组件显示的文本内容。 重点步骤: 在脚本中获取Text组件的援用,并通过代码管制其显示的文本内容。动静更新文本内容。 重点步骤: 依据需要,能够通过代码实现文本的动静更新,比方显示计时器、得分等实时变动的信息。增加动画成果。 重点步骤: 依据游戏的需要,能够为Text组件增加适当的动画成果,加强用户体验。例子代码:在Canvas中创立一个Text组件: 在Hierarchy面板中右键点击Canvas对象,抉择“UI -> Text”创立一个Text子对象。 设置Text组件的款式属性: 在Inspector面板中抉择Text组件,设置其地位、大小、字体、字号、色彩等款式属性。 通过脚本管制Text组件显示的文本内容: using UnityEngine;using UnityEngine.UI;public class ExampleScript : MonoBehaviour{ public Text textComponent; private void Start() { textComponent.text = "Hello, World!"; }}动静更新文本内容: using UnityEngine;using UnityEngine.UI;public class ExampleScript : MonoBehaviour{ public Text textComponent; private int score = 0; private void Update() { score++; textComponent.text = "Score: " + score.ToString(); }}增加动画成果: ...

July 8, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的Button组件的介绍及使用

UGUI的Button(按钮)组件的介绍及应用1. 什么是UGUI的Button组件?UGUI(Unity GUI)是Unity引擎中的一套用户界面零碎,Button(按钮)是其中的一个罕用组件。Button组件能够用于创立可交互的按钮,用户点击按钮时能够触发相应的事件。 2. Button组件工的作原理Button组件通过检测用户的点击事件来触发相应的操作。当用户点击按钮时,Button组件会检测到点击事件,并执行相应的操作,如比调用指定的函数或扭转按钮的状态。 3. Button组件的罕用属性Interactable(可交互):设置按钮是否可交互。如果设置为false,按钮将无奈被点击。Transition(过渡成果):设置按钮的过渡成果,包含色彩、缩放、透明度等。Normal Color(失常状态色彩):设置按钮在失常状态下的色彩。Highlighted Color高(亮状态色彩):设置按钮在高亮状态下的色彩。Pressed Color(按下状态色彩):设置按钮在按下状态下的色彩。Disabled Color(禁用状态色彩):设置按钮在禁用状态下的色彩。4. Button组件的罕用函数onClick.AddListener():为按钮增加点击事件的监听器。onClick.Remove()Listener:移除按钮的点击事件监听器。onClick.Invoke():手动触发按钮的点击事件。5. 示例代码示例1:创立一个简略的按钮using UnityEngine;using UnityEngine.UI;public class ButtonExample : MonoBehaviour{ public Button button; void Start() { button.onClick.AddListener(OnClick); } void OnClick() { Debug.Log("Button clicked!"); }}操作步骤: 创立一个空物体,并将脚本ButtonExample挂载到该物体上。在场景中创立一个按钮,并将该按钮的援用赋值给button变量。运行游戏,点击按钮,控制台将输入"Button clicked!"。注意事项: 确保按钮的OnClick事件曾经绑定到ButtonExample脚本的OnClick函数。示例2:扭转按钮的色彩using UnityEngine;using UnityEngine.UI;public class ButtonExample : MonoBehaviour{ public Button button; void Start() { button.onClick.AddListener(OnClick); } void OnClick() { button.image.color = Color.red; }}操作步骤: 创立一个空物体,并将脚本ButtonExample挂载到该体物上。在场景中创立一个按钮,并将该按钮的援用赋值给button变量。运行游戏,点击按钮,按钮的色彩将变为红色。注意事项: 确保按钮的OnClick事件曾经绑定到ButtonExample脚本的OnClick函数。示例3:禁用按钮using UnityEngine;using UnityEngine.UI;public class ButtonExample : MonoBehaviour{ public Button button; void Start() { button.onClick.AddListener(OnClick); } void OnClick() { button.interactable = false; }}操作步骤: ...

July 7, 2023 · 1 min · jiezi

关于c#:Unity-UGUI的所有组件的介绍及使用

Unity UGUI的所有组件的介绍及应用本文将介绍Unity UGUI中的各个组件,包含它们的具体介绍、用处 1. Text(文本)介绍:Text组件用于在UI界面上显示文本内容。用处:罕用于显示UI界面的题目、按钮标签、提示信息等。2. Image(图片)介绍:Image组件用于在UI界面上显示图片。用处:罕用于显示角色头像、道具图标、背景图片等。3. Button(按钮)介绍:Button组件用于创立可交互的按钮。用处:罕用于触发UI界面的按钮点击事件,例如开始游戏、关上菜单等。4. InputField(输入框)介绍:InputField组件用于接管用户的输出。用处:罕用于接管用户的文本输出,例如用户名、明码等。5. Slider(滑动条)介绍:Slider组件用于显示和管制数值的滑动条。用处:罕用于调整音量、进度条等须要间断数值调整的场景。6. Toggle(复选框)介绍:Toggle组件用于创立复选框。用处:罕用于设置选项的开关状态,例如音效开关、全屏模式等。7. Scrollbar(滚动条)介绍:Scrollbar组件用于管制可滚动内容的滚动条。用处:罕用于显示过长的文本内容或列表,使用户能够滑动查看全部内容。8. Dropdown(下拉菜单)介绍:Dropdown组件用于创立下拉菜单。用处:罕用于提供多个选项供用户抉择,例如游戏难度抉择、语言选择等。9. ScrollRect(滚动视图)介绍:ScrollRect组件用于创立可滚动的视图区域。用处:罕用于显示大量内容,使用户能够高低或左右滑动查看。10. Canvas(画布)介绍:Canvas组件用于创立UI元素的容器。用处:罕用于创立UI界面的根节点,管制UI元素的层级关系和显示成果。11. ScrollSnap(滚动视图疾速定位)介绍:ScrollSnap组件用于在滚动视图中实现疾速定位。用处:罕用于滚动视图中的分页浏览,使用户能够疾速跳转到指定页面。12. GridLayoutGroup(网格布局)介绍:GridLayoutGroup组件用于在UI界面中创立网格布局。用处:罕用于显示多个元素的网格款式布局,例如游戏中的技能面板、背包格子等。13. Mask(遮罩)介绍:Mask组件用于创立遮罩成果。用处:罕用于限度UI元素的可见区域,例如显示部分内容、创立虚构摇杆等。14. ScrollSnapBase(滚动视图根底)介绍:ScrollSnapBase组件是ScrollSnap的根底类。用处:罕用于自定义滚动视图的疾速定位性能。15. RawImage(原始图片)介绍:RawImage组件用于在UI界面上显示原始图片。用处:罕用于显示视频、WebCam等实时图像。16. MaskableGraphic(可遮罩图形)介绍:MaskableGraphic组件是可遮罩图形的根底类。用处:罕用于自定义可遮罩的图形元素,例如实现自定义的遮罩成果。17. LayoutElement(布局元素)介绍:LayoutElement组件用于管制布局元素的大小、地位。用处:罕用于调整UI元素的主动布局形式,例如自适应屏幕大小。18. DropdownOptionData(下拉菜单选项)介绍:DropdownOptionData类用于定义下拉菜单中的选项。用处:罕用于动静生成下拉菜单的选项,例如从数据源中获取选项列表。19. ScrollRectEvent(滚动视图事件)介绍:ScrollRectEvent类用于定义滚动视图的事件。用处:罕用于监听滚动视图的滑动、拖拽等事件,实现自定义的交互逻辑。20. HorizontalLayoutGroup(程度布局)介绍:HorizontalLayoutGroup组件用于创立程度布局。用处:罕用于程度排列多个元素,例如按钮组、菜单栏等。21. VerticalLayoutGroup(垂直布局)介绍:VerticalLayoutGroup组件用于创立垂直布局。用处:罕用于垂直排列多个元素,例如列表、聊天记录等。22. ContentSizeFitter(内容尺寸适应器)介绍:ContentSizeFitter组件用于依据内容主动调整尺寸。用处:罕用于依据内容的大小主动调整UI元素的尺寸,例如文本框、按钮等。23. AspectRatioFitter(宽高比适应器)介绍:AspectRatioFitter组件用于依据宽高比主动调整尺寸。用处:罕用于放弃UI元素的宽高比例不变,适应不同屏幕尺寸。24. CanvasScaler(画布缩放器)介绍:CanvasScaler组件用于调整画布的缩放比例。用处:罕用于适配不同屏幕分辨率,确保UI元素在不同设施上的显示成果统一。之后将会为每个组件的用处及应用形式进行具体解说

July 7, 2023 · 1 min · jiezi

关于c#:Unity的AssetPostprocessor之Model之动画深入解析与实用案例-3

Unity AssetPostprocessor的Model的动画相干的函数批改理论利用在Unity中,AssetPostprocessor是一个十分有用的工具,它能够在导入资源时主动执行一些操作。其中,Model的动画相干的函数批改能够帮忙咱们在导入模型时主动批改动画相干的函数,从而进步咱们的工作效率。本文将介绍如何应用AssetPostprocessor的Model的动画相干的函数批改,并提供多个应用例子。 什么是AssetPostprocessorAssetPostprocessor是Unity中的一个类,它能够在导入资源时主动执行一些操作。咱们能够通过继承AssetPostprocessor并重写其中的办法来实现本人的需要。其中,Model的动画相干的函数批改是AssetPostprocessor中的一个性能,它能够帮忙咱们在导入模型时主动批改动画相干的函数。 Model的动画相干的函数批改在Unity中,咱们能够通过Animator组件来管制模型的动画。Animator组件中蕴含了一些动画相干的函数,例如SetBool、SetFloat、SetInteger等。这些函数能够帮忙咱们管制动画的播放。在导入模型时,咱们能够通过AssetPostprocessor的Model的动画相干的函数批改来主动批改这些函数。 批改SetBool函数咱们能够通过批改SetBool函数来管制动画的播放。例如,咱们能够在导入模型时主动将所有的SetBool函数中的参数名“isRunning”改为“isWalking”,从而管制动画的播放。具体实现如下: using UnityEngine;using UnityEditor;public class ModelPostprocessor : AssetPostprocessor{ void OnPostprocessModel(GameObject go) { Animator animator = go.GetComponent<Animator>(); if (animator != null) { AnimatorController controller = animator.runtimeAnimatorController as AnimatorController; if (controller != null) { foreach (AnimatorControllerParameter parameter in controller.parameters) { if (parameter.type == AnimatorControllerParameterType.Bool) { foreach (AnimationClip clip in controller.animationClips) { AnimationEvent[] events = AnimationUtility.GetAnimationEvents(clip); foreach (AnimationEvent e in events) { if (e.functionName == "SetBool" && e.stringParameter == "isRunning") { e.stringParameter = "isWalking"; AnimationUtility.SetAnimationEvents(clip, events); } } } } } } } }}批改SetFloat函数咱们也能够通过批改SetFloat函数来管制动画的播放。例如,咱们能够在导入模型时主动将所有的SetFloat函数中的参数名“speed”改为“velocity”,从而管制动画的播放。具体实现如下: ...

July 7, 2023 · 3 min · jiezi

关于c#:Unity的AssetPostprocessor之Model深入解析与实用案例-2

Unity AssetPostprocessor中Model相干函数的理论利用Unity AssetPostprocessor是Unity引擎中的一个重要性能,它能够在导入资源时主动一些脚本,以便对资源进行自定义解决。其中,Model相干的函数能够用于对导入的3D模型进行解决,包含批改模型的材质、纹理、网格等属性。本文将介绍Model相干函数的理论利用,并提供多个应用例子。 ModelImporterMaterialNameModelImporterMaterialName函数能够用于批改模型的材质名称。例如,咱们能够将所有模型的材质名称都批改为“DefaultMaterial”。具体实现如下: using UnityEngine;using UnityEditor;public class MyModelPostprocessor : AssetPostprocessor{ void OnPreprocessModel() { ModelImporter importer = assetImporter as ModelImporter; importer.materialName = "DefaultMaterial"; }}ModelImporterMaterialSearchModelImporterMaterialSearch函数能够用于批改模型的材质搜寻门路。例如,咱们能够将所有模型的材质搜寻门路都批改为“Assets/Materials”。具体实现如下: using UnityEngine;using UnityEditor;public class MyModelPostprocessor : AssetPostprocessor{ void OnPreprocessModel() { ModelImporter importer = assetImporter as ModelImporter; importer.materialSearch = ModelImporterMaterialSearch.Local; importer.materialSearchPath = "Assets/Materials"; }}ModelImporterMaterialImportModeModelImporterMaterialImportMode函数能够用于批改模型的材质导入模式。例如,咱们能够将所有模型的材质导入模式都批改为“None”。具体实现如下: using UnityEngine;using UnityEditor;public class MyModelPostprocessor : AssetPostprocessor{ void OnPreprocessModel() { ModelImporter importer = assetImporter as ModelImporter; importer.materialImportMode = ModelImporterMaterialImportMode.None; }}ModelImporterMeshCompressionModelImporterMeshCompression函数能够用于批改模型的网格压缩形式。例如,咱们能够将所有模型的网格压缩形式都批改为“Off”。具体实现如下: using UnityEngine;using UnityEditor;public class MyModelPostprocessor : AssetPostprocessor{ void OnPreprocessModel() { ModelImporter importer = assetImporter as ModelImporter; importer.meshCompression = ModelImporterMeshCompression.Off; }}ModelImporterNormalsModelImporterNormals函数能够用于批改模型的法线计算形式。例如,咱们能够将所有模型的法线计算形式都批改为“Calculate”.具体实现如下: ...

July 6, 2023 · 1 min · jiezi

关于c++:Effective-C-改善程序与设计的55个具体做法读书笔记

1 .让本人习惯C++条款01 视C++为一个语言联邦CObject-Oriented C++Template C++STLC++高效编程守则视状况而变动,取决于你应用C++的哪一部分。条款02 尽量与const,enum,inline替换#define对于单纯常量,最好以const对象或enums替换#defines。对于形似函数的宏(macros),最好改用inline函数替换#defines。条款03 尽可能应用const将某些货色申明为const能够帮忙编译器侦测出谬误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。编译器强制施行bitwise constness,但你编写程序时应该应用“概念上的常量性”(conceptual constness)。当const和non-const成员函数有着本质等价的实现时,令con-const版本调用const版本可防止代码反复。条款04 确定对象应用前已被初始化为内置类型对象进行手工初始化,因为C++不保障初始化他们。构造函数最好应用成员初始值列(member initialization list),而不要在构造函数本体内应用赋值操作(assignment)。初始值列列出的成员变量,其排列秩序应该和它们在class中申明的秩序雷同。为罢黜“跨编译单元之初始化秩序”问题,请以local static对象替换non-local static对象。2. 结构/析构/赋值运算条款05 理解C++默认编写并调用哪些函数编译器能够暗自为class创立default构造函数、copy构造函数和copy assignment操作符,以及析构函数。(C++11开始还有move constructor 和move assignment)。条款06 若不想应用编译器主动生成的函数,就应该明确回绝为驳回编译器主动(暗自)提供的机能,可将相应的成员函数申明为private并且不予实现。应用像uncopyable这样的base calss也是一种做法。(C++11当前能够应用=delete通知编译器删除不须要的成员函数。)条款07 为多态积攒申明virtual析构函数多态性质的base calsses应该申明一个virtual析构函数。如果class带有任何virtual函数,它就应该领有一个virtual析构函数。Classes的设计目标如果不是作为base classes应用,或不是为了具备多态(polymorphically),就不应该申明virtual析构函数。条款08 别让异样逃离析构函数析构函数相对不要吐出异样。如果一个被析构哈你数调用的函数可能抛出异样,析构函数应该捕获人分和异样,并吞下它们或完结程序。如果客户须要对某个操作函数运行期间抛出的异样做出反馈,那么class应该提供一个一般函数(而非析构函数中)执行该操作。条款09 绝不在结构和析构过程中调用virtual函数在结构和析构期间不要调用virtual函数,因为这类调用从不降落至derived class。条款10 令operator=返回一个reference to *this为了实现“连锁赋值”,应该令operator=返回一个reference to *this。条款11 在operator=中解决“自我赋值”确保当对象自我赋值时operator=有良好的行为。其中技术包含比拟“起源对象”和“指标对象”的地址、精心周到的语句程序、以及copy-and-swap。确定任何函数如果操作一个以上的对象,而其中多个对象时同一个对象时,其行为依然正确。条款12 复制对象时勿忘其每一个成分Copying函数应该确保赋值“对象内的所有成员变量”及“所有base class”成分。不要尝试以某个copying函数实现另一个copying函数。应该将独特机能放在第三个函数中,并有两个copying函数独特调用。3. 资源管理条款13 以对象治理资源为了避免资源泄露,请应用RAII对象,它们在构造函数中取得资源并在析构函数中开释资源。两个常被应用的RAII Class别离时tr1::shared_ptr和auto_ptr。前者通常是较好的抉择,因为其copy行为比拟直观。若抉择auto_ptr,赋值动作会使它(被复制物)指向null。(C++11中应用std::shared_ptr、std::unique_ptr和std::weak_ptr代替了两者。)条款14 在资源管理类中小心copying行为复制RAII对象必须一并复制它所治理的资源,所以资源的copying行为决定RAII对象的copying行为。一般常见的RAII class copying行为是:克制copying、履行援用计数法(reference counting)。不过其行为也都能够被实现。条款15 在资源管理类中提供对原始资源的拜访APIs往往要求拜访原始资源(raw resources),所以每一个RAII Class应该提供一个“获得其所治理之资源”的方法。对原始资源的拜访可能经由显式转换或隐式转换。一般而言显式转换比拟平安,隐式转换对客户比拟不便。条款16 成对应用new和delete时要采取雷同模式如果在new表达式中应用[],必须在相应的delete表达式中也应用[]。如如果在new表达式中不应用[],肯定不要在相应的delete表达式中也应用[]。条款17 以独立语句蒋newed对象置入智能指针以独立语句将newed对象存储于(置入)智能指针内。如果不这样做,一旦异样被抛出,有可能导致难以觉察的资源泄露。4. 设计与申明条款18 让接口容易被正确应用,不易被吴用好的接口很容易被正确应用,不容易被误用。应该在所有的接口中致力达成这些性质。“促成正确应用”的方法包含接口的一致性,以及与内置类型的行为兼容。“阻止误用”的方法包含建设新类型、限度类型上的操作,解放对象值,以及打消客户的资源管理责任。条款19 设计class犹如设计typeClass的设计就是type的设计。应该带着和“语言设计者当初设计语言内置类型”时一样的审慎来研究class的设计。条款20 宁以pass-by-reference-to-const 替换 pass-by-value尽量以pass-by-reference-to-const替换pass-by-value。前者通常比拟高效,并可防止切割问题。(slicing problem)以上规定并不适用于内置类型,以及STL的迭代器和函数对象。对它们而言,pass-by-value往往比拟适当。条款21 必须返回对象时,别妄想返回其reference绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象而有可能共事须要多个这样的对象。条款22 将成员变量申明为private切记将成员变量申明为private。这可赋予客户拜访数据的一致性、可轻微划分访问控制、允诺约束条件取得保障,并提供class作者以充沛的实现弹性。protected并不比public更具封装性。条款23 宁以non-member、non-friend替换number函数宁肯拿non-member non-friend函数替换member函数。这样做能够减少封装性、包裹弹性(packing flexibility)和机能扩充性。条款24 若所有参数皆需类型转换,请为此采纳non-number函数如果须要为某个函数的所有参数(包含被this指针所指向的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member。条款25 思考写出一个不摈弃异样的swap函数当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异样。如果你提供一个member swap,也该提供一个non-member swap用来调用前者。对于class(而非template),也请特化std;;swap。调用swap时应针对std::swap应用using申明式,而后调用swap并且不带任何“命名空间资格润饰”。为“用户定义类型”进行std templates全特化时好的,但千万不要尝试在std内退出某些对std而言全新的货色。5. 实现条款26 尽可能延后变量定义式的呈现工夫尽可能延后变量定义式的呈现。这样做可减少程序的清晰度并改善程序效率。条款27 尽量少做转型动作如果能够,尽量避免转型,特地时在重视效率的代码中防止dynamic_casts。如果有个设计须要转型动作,试着倒退无需转型的代替设计。如果转型时必须的,试着将它暗藏于某个函数背地。客户随后能够调用该函数,而不需将转型放进本人的代码内。宁肯应用C++-style(旧式)转型,而不是用新式转型。前者很容易辨识进去,而且也比拟有着分门别类的执掌。条款28 防止返回handles指向对象外部成员防止返回handles(包含references、指针、迭代器)指向外部对象。恪守这个条款可减少封装性,帮忙const成员函数的行为像个const,并将产生dangling handlers的可能性降至最低。条款29 为“异样平安”而致力是值得的异样平安函数(Exception-salf functions)即便产生异样也不会泄露资源或容许任何数据结构毁坏。这样的函数辨别为三种可能的保障:基本型、强烈型、不抛异样型。“强烈保障”往往可能以copy-and-swap实现进去,但“强烈保障”并非对所有函数都能够实现或具备实现意义。函数提供的“异样平安保障”通常最高只等于其所调用之各个函数的“异样平安保障”中的最弱者。条款30 透彻理解inlining的里里外外将大多数inlining限度在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制降级(binary upgradability)更容易,也可使潜在的代码收缩问题最小化,使程序的速度晋升机会最大化。不要只因为function templates呈现在头文件,就将它们申明为inline。条款31 将文件间的编译依存关系降至最低反对“编译依赖最小化”的个别构想是:依赖于申明式,不要依赖于定义式。基于此构想的两个伎俩时Handle classes和Interface classes。程序库头文件应该以“齐全且仅有申明式”(full and declaration-only forms)的模式存在。这种做法不管是否设计templates都实用。6. 继承与面向对象条款32 确定你的public继承塑模出Is-a关系“public继承”象征Is-a。实用于base class身上的每一件事件肯定也实用于derived classes身上,因为每一个“derived class”对象也是一个base class对象。条款33 防止遮掩继承而来的名称derived class内的名称会遮掩base class内的名称。在public继承下素来没有人心愿如此。为了让被遮掩的名称再见天日,可应用using申明式或转交函数(forwarding functions)。条款34 辨别接口继承和实现继承接口继承和实现继承不同。在public继承之下,derived classes总是继承base class的接口。纯虚(pure virtual)函数只具体指定接口继承。非纯虚(impure virtual)函数具体指定接口继承及缺省实现继承。non-virtual函数具体指定接口继承预计强制性实现继承。条款35 思考virtual函数以外的其余抉择virtual函数的代替计划包含NVI手法及Strategy设计模式的多种形式。NVI手法本身时一个非凡模式的Template Method设计模式。将机能从成员函数移到class内部函数,带来的一个毛病时,非成员函数无法访问class的non-public成员。tr1::function(C++11曾经移到std::function)对象的行为就像个别函数指针。这样的对象可接收“与给定之指标签名式(target signature)兼容”的所有可调用物(callable entities)。条款36 绝不从新定义继承而来的non-virtual函数相对不要从新定义继承而来的non-virtual函数。条款37 绝不从新定义继承而来的缺省参数相对不要从新定义一个继承而来的缺省参数值,因为缺省参数值是动态绑定,而virtual函数——你惟一应该覆写的定西——确是动静绑定。条款38 通过复合塑模出has-a或“依据某物实现出”复合(composition)的意义和public继承齐全不同。在利用域(application domain),复合意味着has-a(有一个),在实现域(implementation domain),复合意味着is-implemented-in-terms-of(依据某物实现出)。条款39 理智而审慎的应用private继承Private继承意味着is-implemented-in-terms-of(依据某物实现出)。它通常比复合(composition)的级别低。然而当derived class 须要拜访protected base class的成员,或须要从新定义继承而来的virtual函数时,这么设计时正当的。和复合(composition)不同,private继承能够造成empty base最优化。这对致力于“对象尺寸最小化”的程序库开发者而言,可能很重要。条款40 理智而审慎的应用多重继承多重继承比繁多继承简单。它可能导致新的歧义性,以及对virtual继承的须要。virtual继承会减少大小、速度、初始化(及赋值)复杂度等老本。如果virtual base classes不带任何数据,将时最具备实用价值的状况。多重继承确实有正当用处。其中一个情节波及“public继承某个interface class”和“private继承某个帮助实现的class”的两相组合。7. 模板与泛型编程条款41 理解隐式接口和编译器多态classes和templates都反对接口(interface)接多态(polymorphism)。对classes而言接口时显式的(explicit),以函数签名为核心,多态则是通过virtual函数产生于运行期。对于templates参数而言,接口是隐式的(implicit),奠基于无效表达式。多态则时通过template具现化和函数重载 解析(function overloading resolution)产生于编译期。条款42 理解typename的双重意义申明template参数时,前缀关键字class和typename可调换。请应用关键字typename标识嵌套隶属类型名称;但不得在base class lists(基类列)或member initialization list(成员初始值列)内以它最为base class 修饰符。条款43 学习解决模板化基类内的名称可在derived class templates内通过this->指涉base class templates内的成员名称,或由一个明确写出的“base class资格修饰符”实现。条款44 将与参数无关的代码抽离templatesTemplates生成多个classes和多个函数,所有任何template代码都不该与某个造成收缩的template参数产生相依关系。因非类型模板参数(non-type template parameters)而造成的代码收缩往往能够打消,做法是以函数参数或class成员变量替换template参数。条款45 使用成员函数末班承受所有兼容类型请应用member functions templates(成员函数模板)生成“可承受所有兼容类型”的函数。如果你申明member templates用于“泛化copy结构”或“泛化assignment操作”,你还是须要申明失常的copy构造函数和copy assignment操作符。条款46 须要类型转换时请为模板定义非成员函数当编写一个class template,而它所提供的“与此template相干的”函数反对“所有参数之隐式类型转换”时,请将那些函数定义为“class template外部的friend函数”。条款47 请应用traits classes体现类型信息Traits classes使得“类型相干信息”在编译期可用。它们以template和"template特化"实现实现。整合重载技术(overloading)后,traits calsses有可能在编译器对类型执行if...else测试。条款48 意识template元编程Template metaprogramming(TPM,模板元编程)可将工作由运行期移到编译期,因此得以实现晚期谬误侦测和更高的执行效率。TMP可被用来生成“基于政策抉择组合”(based on combinations of policy choices)的客户定制代码,也可用来防止生成对某些非凡类型并不适宜的代码。8. 定制new和delete条款49 理解new-handler的行为set_new_handler容许客户指定一个函数,在内存调配无奈取得满足时被调用。Nothrow new是一个颇为局限的工具,因为它只实用于内存调配,后继的结构函数调用还是可能抛出异样。条款50 理解new和delete的正当替换机会有许多理由须要写个自定义的new和delete,包含改善效力、对heap使用谬误进行调试、收集heap应用信息。条款51 编写new和delete时需猛攻惯例operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无奈满足内存需要,就该调用new-handler。它也应该有能力解决0 byte申请。class专属版本则还应该解决“比正确大小更大的(谬误)申请”。operator delete应该在收到null指针时不做任何事。class专属版本则还应该解决“比正确大小更大的(谬误)申请”。条款52 写了placement new也要写placement delete当你写一个placement operator new,请确定也写出对应的placement operator delete。如果没有这样做,你的程序可能会产生隐微而连续不断的内存泄露。当你申明placement new和placement delete时,确定不要有意识(非故意)的覆盖了它们的失常版本。9. 杂项探讨条款53 不要轻忽编译器的正告请庄重看待编译器收回的正告信息。致力在你的编译器的最高(最严苛)正告级别下争取“无任何正告”的荣誉。不要适度依赖编译器的报警能力,因为不同的编译器看待事件的态度并不相同。一旦移植到另一个编译器上,你本来依赖的正告信息有可能隐没。条款54 让本人相熟包含TR1在内的规范程序库C++规范库的次要机能由STL、iostreams、locales组成。并蕴含C99规范程序库。TR1增加了智能指针(例如tr1::shared_ptr)、一般化函数指针(tr1::function)、hash-based容器(unorderd_map,unordered_set)、正则表达式(regular expressions)以及另外10个组件的反对。TR1本身只是一份标准。为了取得TR1提供的益处,你须要一份实物。一个好的实物起源时Boost。条款55 让本人相熟BoostBoost是一个社群,也是一个网站。致力于收费、源码凋谢、同僚复审的C++程序库开发。Boost在C++标准化过程中表演深具影响力的角色。Boost提供许多TR1组件的实现品,以及其余许多程序库 ...

July 6, 2023 · 1 min · jiezi

关于c:CSDN-逃离计划-hyperscan-从安装到写出第一个测试demo

hyperscan 作为和intel深度绑定的政策匹配工具,提供了及其弱小的正则匹配性能,并提供接口,不便对匹配后果进行二次操作。 我在学习hyperscan时,在各大论坛并没有找到比拟齐备并且具体解说,很多只是提到了函数库大略时干什么的,索性将本人理解到的货色,具体的记录下来,也算是本人对hyperscan的一次坚固 hyperscan 是英特尔开源的一款正则匹配工具,与intel芯片深度绑定,intel对其有专门的优化,因而在整体的匹配效率上,相较于其余正则计划,处于一个较为当先的地位。 hyperscan反对pcre 正则规定,现有的次要利用计划大都是基于pcre做的匹配。 样例代码放在了github上,前面会贴出来。 注: 本文演示环境为 ubuntu 22.04 hyperscan下载安装下载intel在github上凋谢了源码,通过git即可下载,因为github,在国内拜访不敌对,在gitee上也有相干开源代码githubgit clone https://github.com/intel/hyperscan.gitgiteegit clone https://gitee.com/tzichengchew/hyperscan.git依赖hyperscan 应用cmake编译cmake等根底库装置不再赘述, 须要依赖boost Boost DownloadsragelRagel State Machine Compiler (colm.net)git clone https://github.com/adrian-thurston/ragel.git* colmgit clone https://github.com/adrian-thurston/colm.git其中ragel的装置须要clom反对在官网均能找到下载地址。或者git地址 装置装置boost bash bootstrap.sh && ./b2 && ./b2 install 装置ragel不倡议编译装置,坑很多 sudo apt install ragel编译装置hyperscan 创立一个目录 mkdir hyperscan_comp执行编译命令 cmake $HYPERSCAN_PATHmake && make install 须要蛮久的。遇到一个十分辣手的问题: undefined reference to `avx2_memset'undefined reference to `corei7_memset'…………https://github.com/intel/hyperscan/issues/292#issuecomment-762635447亲测无效。我在另外一台设施上测试发现并没有报错,预计可能是虚拟机cpu配置问题,后面提到了,hyperscan与intel深度绑定。 批改过cmake/build_wrapper.sh脚本后,就能够执行cmake命令了 为避免产生的cmake文件搞混了源文件,这里倡议建设一个新的目录,执行cmake 须要留神的是,在应用hyperscan时,动静库要比动态库应用绝对不便,批改CMakeCache.txt文件,依据版本不同,所在行数也不同。 BUILD_STATIC_AND_SHARED:BOOL=OFF->BUILD_STATIC_AND_SHARED:BOOL=ON批改过后即可执行make && make install hyperscan 简略应用hyperscan整体的应用流程次要分为编译器和运行期 ...

July 5, 2023 · 2 min · jiezi

关于c++:C面试八股文如何避免死锁

某日二师兄加入XXX科技公司的C++工程师开发岗位第31面: 面试官:什么是锁?有什么作用? 二师兄:在C++中,锁(Lock)是一种同步工具,用于爱护共享资源,避免多个线程同时拜访,从而防止数据竞争和不统一。 面试官:有哪些锁? 二师兄:从品种上分,能够分为一般锁、读写锁、递归锁等品种。 二师兄:从实现上分,能够分为互斥锁、自旋锁、信号量、条件变量等。 面试官:互斥锁如何应用? 二师兄:在C++11之前,C++便准层面并没有定义锁,锁的利用要依赖于平台。Linux下应用pthread库中的mutex; #include <pthread.h>pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_lock(&mutex_);//被爱护的区域pthread_mutex_unlock(&mutex_);二师兄:C++11引入了std::mutex,对立了各个平台上互斥锁的应用:#include <mutex>std::mutex mutex_;mutex_.lock();//被爱护的区域mutex_.unlock();面试官:pthread_mutex和std::mutex有没有非阻塞的api? 二师兄:有的,别离是pthread_mutex_trylock()和try_lock(),当获取不到锁时这两者并不阻塞以后线程,而是立刻返回。须要留神的是,当pthread_mutex_trylock()获取到锁时返回0,而std::mutex::try_lock()办法获取不到锁时返回false。 面试官:std::lock_guard和std::unique_lock用过吗? 二师兄:用过。 面试官:两者有什么相同点和不同点? 二师兄:相同点是两者都应用RAII(资源获取即初始化)技术实现的锁,反对主动上锁,主动解锁。 二师兄:不同点次要包含三个方面: 1.灵活性:std::unqiue_lock的灵活性要高于std::lock_gurad,std::unique_lock能够在任何工夫解锁和锁定,而std::lock_guard在结构时锁定,在析构时解锁,不能手动管制。 2.所有权:std::unique_lock反对所有权转移,而std::lock_gurad不反对。 3.性能:因为std::unique_lock的灵活性更高,它的性能可能会略微低一些。 面试官:能实现一个lock_gurad吗? 二师兄:我尝试一下: class lock_guard{ explicit lock_guard(std::mutex& m):mutex_(m) { mutex_.lock(); } ~lock_guard() { mutex_unlock(); }private: std::mutex& mutex_;};面试官:为什么会产生死锁? 二师兄:当过程A持有锁1申请锁2,过程B持有锁2申请锁1时,两者都不会开释本人的锁,两者都须要对方的锁,就会造成死锁。当然事实中可能比这要简单,但原理是雷同的。 面试官:如何防止死锁? 二师兄:次要从以下几个方面动手: 1.防止循环期待,如果须要在业务中获取不同的锁,保障所有业务依照雷同的程序获取锁。 2.应用超时锁,当锁超时时,主动开释锁。 3.应用try_lock,当锁被占用时,返回false并继续执行。 4.锁的粒度尽量要小,只爱护竟态数据而不是整个流程。 面试官:晓得adopt_lock_t/defer_lock_t/try_to_lock_t这三种类型的用法吗? 二师兄:额。。不晓得。。 面试官:好的,回去等告诉吧。 让咱们来看看最初一个问题: 晓得adopt_lock_t/defer_lock_t/try_to_lock_t这三种类型的用法吗?adopt_lock_t/defer_lock_t/try_to_lock_t都是空类,次要示意std::lock_gurad和std::unqiue_lock的默认结构中的操作: adopt_lock_t:默认互斥量已被以后线程锁定,不应用lock()办法对互斥量加锁: std::mutex mtx_;mtx_.lock(); //lock{ std::lock_guard<std::mutex> lock_(mtx_,std::adopt_lock); //这里默认以后线程曾经对mtx_加过锁 ...}//unlockdefer_lock_t:尽管我领有了std::mutex的援用,然而在构造函数中并不调用lock()办法对互斥量加锁: std::mutex mtx_;{ std::unique_lock<std::mutex> ulock_(mtx_,std::defer_lock); //这里并没有加锁 ulock_.lock(); if(ulock_.owns_lock()) { //locked }else { //unlocked }}//if locked,unlocktry_to_lock_t:在构造函数执行是并不是应用lock()办法加锁,而是应用try_lock()办法加锁: ...

July 4, 2023 · 1 min · jiezi

关于c:csdn-逃离计划-如何优雅的在windows平台用命令行写代码

为什么要这么做之前为了写一些window环境下的小工具,想要写一个.exe 间接运行,与linux环境下相似,间接应用命令行的模式实现一些根本的计算之类的操作,当理论要做的时候,首先就发现了一个十分大的问题:依照c语言编译过程来说,首先须要编写一个.c 文件,而后通过这个.c 文件与编译链接等操作,最终生成一个可能在linux环境下运行的可执行文件。然而,在windows环境下,零碎并没有集成gcc之类的工具,之前写这类工具,都是应用vs套件主动生成,包含依赖环境等都是主动装置好的,一旦波及到文件挪动之类,环境变量常常会呈现各种各样的问题,解决起来很头疼。因而,本文次要就来搞一个小demo,看一下,windows一个小的命令行工具,想要尽可能疾速的搭建一个精简的环境大略须要怎么做。(偷懒方法,其实也是搭建了一个小型linux环境,技术细节须要深究,暂不做思考) 装置依赖在linux环境下,咱们编译一个.c 文件,使其生成一个可执行文件,须要手动执行一条命令, gcc demo.c -o test 当然,更加简单的零碎须要用到穿插编译等,这里暂不做探讨。然而windows中没有这种命令,因而就须要借助c/c++ 编译工具来实现,我这里选用的Cygwin, 从官网下载之后装置该工具,傻瓜式装置,这里不再赘述,须要留神的是,cygwin默认装置大多数的linux命令,比方’ls’,'rm’等。在抉择软件装置形式能够抉择在线装置,抉择装置源,之后会让你抉择须要装置的软件,在全副里抉择gcc-core g++。当cygwin装置胜利后,关上cygwin能够发现生成了一个相似于linux环境的命令行环境。如果在这里间接编写软件,并且应用gcc编译的话,确实能生成一个exe文件,并且在命令行中能够间接运行,然而,此时应用图形化界面关上生成的可执行文件,就会间接报错,cygwin1.dll 与 libstd++*.dll 文件缺失,这实际上并不是缺失,而是装置了cygwin曾经装置了然而windows无奈辨认,找到cygwin的装置目录,关上bin,你会发现所有的文件都有, 只不过没有被windows辨认到这时候,只须要增加一个环境变量 将cygwin/bin的目录增加到环境变量中的PATH中去,就能够解决报错的问题。测试

July 4, 2023 · 1 min · jiezi

关于c++:C面试八股文如何实现一个strncpy函数

某日二师兄加入XXX科技公司的C++工程师开发岗位第31面: 面试官:strcpy函数应用过吧? 二师兄:用过。 面试官:这个函数有什么作用? 二师兄:次要用做字符串复制,将于字符从一个地位复制到另一个地位。 面试官:strncpy函数也应用过吧,和strcpy有何不同? 二师兄:strncpy多了一个size_t的参数,用于防止缓冲区溢出。 面试官:是否实现一个strncpy函数? 二师兄:好的。 void strncpy(char *dest, char *src, size_t n){ for (size_t i = 0; i < n; i++) { *(dest + i) = *(src + i); }}面试官:额。。如果strlen(src) < n会产生什么? 二师兄:嗯。。那要做个判断。。 void strncpy(char *dest, char *src, size_t n){ size_t len = strlen(src) > n ? n : strlen(src); for (size_t i = 0; i < len; i++) { *(dest + i) = *(src + i); }}面试官:如果strlen(dest) < n呢? ...

July 3, 2023 · 2 min · jiezi

关于c++:C实现四叉树

四叉树是一种空间索引(划分)技术,通过递归地将一整块区域平均划分为4个子区域,每个区域托管肯定数量的二维点,于是任意一个二维点都能够依据它的坐标疾速找到所述的子区域,失去它的邻点。 具体介绍略过,只有会实现二叉树的二分查找,就不难领会四叉树划分的思维。因为查找邻点的速度十分快,所以罕用于游戏中的碰撞检测,GIS的地理位置索引等。 上面是我实现的一种传统四叉树。 节点定义: #include <vector>#include <cstdlib>#include <ctime>#include <iostream>//二维数据点定义typedef struct Point_2D { int x; int y;}Point;//节点定义typedef struct Quad_Tree_Node { Point start_xy; //左上角起始点 int width; //宽度 int height; //高度 int capacity; //节点容量 bool is_leaf; //叶节点标记 std::vector<Point> points; //存储的二维点 Quad_Tree_Node* lu_child; //子节点,左上 Quad_Tree_Node* ru_child; //子节点,右上 Quad_Tree_Node* lb_child; //子节点,左下 Quad_Tree_Node* rb_child; //子节点,右下 int depth; //以后节点深度}Quad_Node;二维数据点构造只有横纵坐标,也能够携带别的信息。四叉树节点中须要保留所属子区域的信息,我应用左上角起始点+宽度+高度来定义一块区域。设置了节点容量来限度一块区域能保留的数据量,如果超过容量,节点就要持续决裂。 创立节点办法: Quad_Node* Quad_Tree::create_node_(const Point& start, const int& w, const int& h) { Quad_Node* new_node = new Quad_Node; new_node->start_xy = start; new_node->width = w; new_node->height = h; new_node->capacity = _set_capacity; new_node->is_leaf = true; new_node->lu_child = nullptr; new_node->lb_child = nullptr; new_node->ru_child = nullptr; new_node->rb_child = nullptr; return new_node;}创立节点办法须要左上起始点、宽度和高度三个入口参数。 ...

July 3, 2023 · 4 min · jiezi

关于c++:C面试八股文技术勘误

人不知;鬼不觉,《C++面试八股文》曾经更新30篇了,这是我第一次写技术博客,因为集体能力无限,呈现了不少纰漏,在此向各位读者小伙伴们致歉。 为了不误导更多的小伙伴,当前会不定期的出勘误文章,请各位小伙伴注意。 在《C++面试八股文:C++中,设计一个类要留神哪些货色?》一文中, #include <iostream>struct Foo{};struct Goo{ void f1(Foo& f){std::cout <<"non const function" << std::endl;} void f1(const Foo& f){std::cout <<"const function" << std::endl;}};int main(int argc, char const *argv[]){ Foo foo; Goo goo; goo.f1(foo); //无奈通过编译,error: ‘void Goo::f1(Foo)’ cannot be overloaded with ‘void Goo::f1(Foo)’ return 0;}这里的例子f1和f2办法的参数应该是Foo f和const Foo f,这才是顶层const。在此感激知乎用户 退乎 的揭示。 在《C++面试八股文:std::string是如何实现的?》一文中, 有std::string重载的相干问题,我曾经在 技术勘误:《C++面试八股文:std::string是如何实现的?》 一文中做了具体阐明,在此再次感激知乎用户 肃穆 的斧正。 在《C++面试八股文:override和finial关键字有什么作用?》一文中,final 误拼为 finial,感激知乎用户 DiaoYan 的斧正。 同时,这张内存布局图也有谬误, 应该是这样的: 感激知乎用户 清越 的斧正。 在《C++面试八股文:std::vector理解吗?》一文中, 面试官:push_back和emplace_back有什么区别?除了文中所说的不同点,还要一点:emplace_back能够传入构造函数结构对象,而push_back只能拷贝或挪动对象。 ...

July 1, 2023 · 2 min · jiezi

关于c++:C面试八股文什么是空指针野指针悬垂指针

某日二师兄加入XXX科技公司的C++工程师开发岗位第30面: 面试官:什么是空指针? 二师兄:个别咱们将等于0/NULL/nullptr的指针称为空指针。空指针不能被解援用,然而能够对空指针取地址。 int* p = nullptr; //空指针*p = 42; //空指针不能够解援用int** pp = &p //空指针能够取地址面试官:你晓得0/NULL/nullptr三者之间的区别吗? 二师兄:尽管三者都能定义空指针,但三者类型不同。 二师兄:0是int类型,NULL在g++下是一个宏定义,而nullptr是有类型的; #define NULL ((void *)0)typedef decltype(nullptr) nullptr_t;sizeof(0);// 4sizeof(NULL);//8sizeof(nullptr);//8二师兄:在函数重载时,会依据实参的类型抉择重载函数:#include <iostream>void fun(int) {std::cout << "int" << std::endl;}void fun(int*) {std::cout << "int*" << std::endl;}void fun(nullptr_t) {std::cout << "nullptr_t" << std::endl;}int main(int argc, char const *argv[]){ fun(0); //编译通过,匹配fun(int) fun(NULL); //编译失败,能够匹配 fun(int) fun(int*) fun(nullptr_t) fun(nullptr); //编译胜利,匹配fun(nullptr_t) return 0;}二师兄:在C++11之后,倡议应用nullptr定义空指针,因为它时有类型的,编译器可能对它进行类型查看。 面试官:什么是野指针? 二师兄:野指针突出一个野字,这个野就是状态未知的。它可能指向一块未知的区域: int* p; //野指针,指针未初始化*p = 42; //对野指针解援用,未定义的操作面试官:什么是垂悬指针? 二师兄:垂悬指针是指指针指向的内容已被开释,指针指向的对象的生命周期已完结。 int* p = new int(42);delete p;*p = 1024; //垂悬指针,指针指向的对象已被开释int* p = nullptr;{ int i = 42; p = &i;}*p = 1024; //垂悬指针,指向的对象的生命周期已完结面试官:如何解决空指针、野指针、垂悬指针带来的问题? ...

June 30, 2023 · 1 min · jiezi

关于c++:C面试八股文什么是构造函数

某日二师兄加入XXX科技公司的C++工程师开发岗位第29面: 面试官:什么是构造函数? 二师兄:构造函数是一种非凡的成员函数,用于创立和初始化类的对象。构造函数的名称与类的名称雷同,并且没有返回类型。构造函数在对象被创立时主动调用。 struct Foo{ Foo(int v):val(i){} //构造函数private: int val;};面试官:什么是默认构造函数?什么状况下默认构造函数会被创立? 二师兄:没有任何参数的构造函数(所有参数都要默认参数的构造函数也是)。个别定义类时没有显式的申明任何构造函数,默认构造函数会被编译器主动创立。 struct Foo{private: int val;}; //此时默认构造函数会被创立二师兄:当然就算为类自定义了构造函数,咱们也能够通过Foo()=default为类显式定义一个默认构造函数。 面试官:什么是构造函数初始值列表? 二师兄:是为了初始化成员变量所传入的参数列表: class Foo{public: Foo(int i, long l):ival_(i),lval_(l){} //初始值列表private: int ival_; long lval_;};面试官:下面的构造函数和以下的构造函数有什么区别?Foo(int i, long l){ ival_ = i; lval_ = l;}二师兄:这是初始化与赋值的区别。这段代码中的ival_和lval_先被默认初始化,而后被赋值。而初始化列表是间接初始化,少了一步赋值。 面试官:如果把构造函数写成Foo(int i, long l):lval(l),ival_(i){}会有什么问题吗? 二师兄:成员初始化的程序尽量要和定义的程序保持一致。如上面的代码,就是未定义的: class Foo{public: Foo(int i):jval_(i),ival_(jval_){} //未定义的行为,因为ival先被初始化,这时候jval是未定义的private: int ival_; int jval_;};面试官:什么是委托构造函数? 二师兄:构造函数在结构对象的时候把一部分工作委托给其余构造函数进行结构,这是C++11引入的新个性: class Foo{public: Foo(int i, long l):ival_(i),lval_(l){} Foo(int i):Foo(i,0){} //委托给Foo(int i, long l)private: int ival_; long lval_;};面试官:如果构造函数没有初始化任何成员变量,应用这个构造函数会产生什么? ...

June 29, 2023 · 1 min · jiezi

关于c++:C面试八股文知道stdunorderedsetstdunorderedmap吗

某日二师兄加入XXX科技公司的C++工程师开发岗位第27面: 面试官:晓得std::unordered_set/std::unordered_map吗? 二师兄:晓得。两者都是C++11引入的新容器,和std::set和std::map性能相似,key惟一,unordered_map的value可变。 二师兄:不同于set/map,unordered_set/unordered_map都是无序容器。 面试官:那你晓得它们底层怎么实现的吗? 二师兄:两者底层应用哈希表实现,因而插入、删除和查找操作的均匀工夫复杂度为常数工夫O(1)。 面试官:既然均匀复杂度是O(1),那么是不是能够取代set和map了? 二师兄:这里是均匀的工夫复杂度。哈希表插入、删除和查找操作的最差工夫复杂度是O(n),要比set/map的O(log n)大。 面试官:那你感觉哪些场景适宜set/map,哪些场景适宜unordered_set/unordered_map? 二师兄:set/map实用于须要有序存储和疾速查找的场景,而unordered_set/unordered_map实用于须要疾速插入和查找的场景。 面试官:unordered_set/unordered_map对于key的类型有什么要求吗? 二师兄:因为unordered_set/unordered_map底层采纳哈希表,所以在应用自定义类型作为key的时候,须要通知编译器如何计算此类型的hash值,同时还要通知编译器如何判断两个自定义类型的对象是否相等。以下代码无奈通过编译: #include <iostream>#include <unordered_set>struct Foo{ std::string str; int val;};int main(int argc, char const *argv[]){ std::unordered_set<Foo> uset; uset.insert({"42",42}); uset.insert({"1024",1024}); return 0;}二师兄:此时须要为Foo类型实现bool operator==(const Foo& o) const函数和size_t operator()(const Foo& f) const仿函数,能力通过编译:#include <iostream>#include <unordered_set>struct Foo{ std::string str; int val; bool operator==(const Foo& o) const { return str == o.str && val == o.val; }};struct Hash{ size_t operator()(const Foo& f) const { return std::hash<std::string>()(f.str) ^ std::hash<int>()(f.val); }};int main(int argc, char const *argv[]){ std::unordered_set<Foo,Hash> uset; uset.insert({"42",42}); uset.insert({"1024",1024}); return 0;}二师兄:当然咱们也能够应用std::function或者lambda来代替仿函数,目标都是为了使得编译器晓得如何计算自定义类型的哈希值。 ...

June 28, 2023 · 1 min · jiezi

关于c++:c中qt字符串链式调用的问题

c++有一个代码看起来挺奇怪 QString qstr = "aaa";char* cstr = qstr.toStdString().c_str(); //errstd::string std_str = qstr.toStdString();char *cstr = std_str.c_str(); //ok应用链式调用时候就出错了而离开调用就是好的问问chatgpt才晓得c_str()返回的的是std string的底层数据,如果std string曾经销毁了这个字符串就是野指针了,而离开调用的时候std_str变量到函数结尾才开释就是好的

June 28, 2023 · 1 min · jiezi

关于c++:C面试八股文用过stdsetstdmap吗

某日二师兄加入XXX科技公司的C++工程师开发岗位第27面: 面试官:用过std::set/std::map吗? 二师兄:用过。 面试官:能介绍一下二者吗? 二师兄:std::set是一个有序的汇合,其中的元素是惟一的,即每个元素只能呈现一次。个别用于去重和主动排序。 二师兄:std::map同样是有序组合,只不过它不止有key,每个key还对用一个value。其中key是惟一,不可反复,然而value却没有限度。key/value也被称为键值对。 面试官:晓得他们底层应用什么数据结构存储数据的吗? 二师兄:两者都是应用红黑树作为底层的数据结构。红黑树是一种主动均衡的二叉树,它确保插入、删除和查找操作的工夫复杂度都是O(log n)。 面试官:set/map对于key的类型有什么要求吗? 二师兄:因为set/map被称为有序容器,所以对插入进去的key有排序的要求。个别须要为类型实现<比拟办法,以下代码无奈通过编译: #include <iostream>#include <set>struct Foo{ Foo(int v):val(v){} int val;};int main(int argc, char const *argv[]){ std::set<Foo> iset; iset.insert(Foo(1024)); iset.insert(Foo(42)); for(auto it = iset.begin(); it != iset.end(); ++it) { std::cout << it->val << std::endl; } return 0;}二师兄:此时须要为Foo类型实现bool operator<(const T&, const T&)函数,能力通过编译:bool operator<(const Foo& lhs,const Foo& rhs) {return lhs.val < rhs.val;}面试官:依照你的办法,能够实现从小到大的排序。如何实现从大到小的排序? 二师兄:set/map类模板的第二个模板参数能够传入比拟类型,默认比拟类型是std::less<_Key>,咱们能够传入std::greater<T>,此时须要实现bool operator>(const T&, const T&)函数。 二师兄:还有一种办法是手写一个仿函数,重载bool operator()(const T, const T) const函数用于比拟两者的大小: ...

June 27, 2023 · 1 min · jiezi

关于c++:C面试八股文stddeque用过吗

某日二师兄加入XXX科技公司的C++工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,根本没用过。 面试官:为什么? 二师兄:因为应用它的场景很少,大部分须要性能、且须要主动扩容的时候应用vector,须要随机插入和删除的时候能够应用list。 面试官:那你晓得STL中的stack是如何实现的吗? 二师兄:默认状况下,stack应用deque作为其底层容器,但也能够应用vector或list作为底层容器。 面试官:你感觉为什么STL中默认应用deque作为stack的底层容器吗? 二师兄:额。。(stack也不须要双端插入啊,不应该vector更好吗。。)不是很分明。。 面试官:没关系。那你晓得deque是如何实现的吗? 二师兄:与vector内存空间间断不同,deque是局部间断的。deque通常保护了一个map(不是std::map),map的每个元素指向一个固定大小的chunk。同时保护了两个指针,指向头chunk和尾chunk。在deque的头部或尾部插入元素时,deque会找到头部或尾部的指针,并通过指针找到对应的chunk。如果chunk中还有未被元素填充的地位,则将元素填充到数组中,如果此指针指向的chunk曾经被元素填满,则须要从新开拓一块固定大小的chunk,并将chunk记录在map中。 面试官:deque的查找、插入、删除的工夫复杂度是什么? 二师兄:dqueue查找的工夫复杂度是O(N),插入要分状况,如果是头插和尾插,工夫复杂度为O(1),如果是两头插入,则是O(N)。删除元素和插入元素的工夫复杂度雷同。 面试官:好的。面试完结,回去等告诉吧。 让咱们来看一下二师兄的体现: 为什么STL中默认应用deque作为stack的底层容器吗?STL默认抉择deque最为stack的底层容器必定是有起因的。vector和list同样能够作为deque的底层容器,让咱们比拟一下三个容器的差别:(只思考头插和尾插,因为stack不须要随机插入) dequevectorlist插入O(1)O(1)O(1)删除O(1)O(1)O(1)从上表中看到,三种容器的插入和是删除的工夫复杂度雷同。 然而如果间断插入时,状况发生变化。vector的capacity被耗尽,元素产生搬移。 list倒没有这个顾虑,然而当元素尺寸很小时,list的空间利用率太低。 deque尽管遍历效率不如vector、随机插入效率不然list,但stack并不需要这两种操作,所以deque是stack底层容器的最佳抉择。 明天的面试分享到这里就完结了,让咱们持续期待二师兄的体现吧。 关注我,带你21天“精通”C++!(狗头)

June 26, 2023 · 1 min · jiezi

关于c++:C面试八股文stdarray如何实现编译器排序

某日二师兄加入XXX科技公司的C++工程师开发岗位第25面: 面试官:array相熟吗? 二师兄:你说的是原生数组还是std::array? 面试官:你感觉两者有什么区别? 二师兄:区别不是很大,原生数组(非动静数组)和std::array都在栈上开拓空间,初始化的时候须要提供数组长度,且长度不可扭转。有一点区别的是,std::array提供了平安的下标拜访办法at,当下标越界时会抛出异样。 面试官:还有其余区别吗? 二师兄:让我想想。。。在当作参数传递时,原生数组会进化为指针,而std::array会保留类型和长度信息。 面试官:好的。晓得空数组的长度和长度为0的std::array对象有什么区别吗? 二师兄:(这也太刁钻了吧。。)空数组的长度应该是0,然而长度为0的std::array对象的长度是1,因为它是空类。 面试官:如果一个类型的拷贝构造函数和拷贝赋值运算符是被删除的,能够应用std::array存储它吗? 二师兄:当然能够。只是不能传递这个std::array对象,而只能传递这个对象的援用或指针。 面试官:你感觉array和vector的性能哪个好? 二师兄:array的性能更好,array的内存调配在栈上,编译时候确定须要在栈上开拓的空间。vector的元素存在堆上,须要开拓和开释堆内存。但vector更灵便,如果能提前确定数据量,应用reserve函数一次性开拓空间,性能和array没有太大的差距。 面试官:好的。你方才说array能在编译时候确定须要在栈上开拓的空间,请问array在编译时还可能做些什么? 二师兄:比方给定一个array,咱们能够在编译时求它所以元素的和。 #include <iostream>#include <array>constexpr int sum(auto arr){ int res = 0; for (size_t i = 0; i < arr.size(); i++) res += arr[i]; return res;}int main(int argc, char const *argv[]){ constexpr std::array arr = {1,2,3,4,5,6,7,8,9}; constexpr int res = sum(arr); std::cout << res << std::endl; return 0;}//g++ test.cpp -std=c++20 面试官:好的,应用array实现编译期排序,没问题吧? 二师兄:(终于,该来的还是来了!)我尝试一下: #include <iostream>#include <array>constexpr auto sort(auto arr){ for ( int i = 0; i < arr.size() -1; i++) { for ( int j = 0; j < arr.size() - i -1; j++) { if (arr[j] < arr[j + 1]) { auto tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp; } } } return arr;}int main(int argc, char const *argv[]){ constexpr std::array arr {10.5, 28.6, 4.4, 23.8, 12.4, 3.8, 19.7, 17.5, 19.1, 0.6, 1.9, 1.5, 25.4, 5.4}; constexpr auto arr2 = sort(arr); for (size_t i = 0; i < arr2.size(); i++) { std::cout << arr2[i] << std::endl; } return 0;}//g++ test2.cpp -std=c++20二师兄:应用了C++20的auto参数类型主动推断个性,实现了相似于泛型的成果。arr能够是任何实现了constexpr opearator<函数的类型。 ...

June 25, 2023 · 1 min · jiezi

关于c++:C面试八股文stdvector和stdlist如何选择

某日二师兄加入XXX科技公司的C++工程师开发岗位第24面: 面试官:list用过吗? 二师兄:嗯,用过。 面试官:请讲一下list的实现原理。 二师兄:std::list被称为双向链表,和C中手写双向链表实质上没有大的区别。list对象中有两个指针,一个指向上一个节点(node),一个指向下一个节点(node)。 二师兄:与手写双向链表不同的是,list中有一个base node,此node并不存储数据,从C++11开始,此node中蕴含一个size_t类型的成员变量,用来记录list的长度。 二师兄:所以说从C++11开始,size()的工夫复杂度是O(1),在此之前是O(N)。 面试官:是每个node都蕴含一个记录长度的成员变量吗? 二师兄:不是,GCC中的实现只有在header node上记录了长度信息,其余node并没有记录。 struct _List_node_base{ _List_node_base* _M_next; _List_node_base* _M_prev; ...};struct _List_node_header : public _List_node_base{#if _GLIBCXX_USE_CXX11_ABI std::size_t _M_size;#endif...}; 面试官:增加和删除元素会导致迭代器生效吗? 二师兄:并不会,因为在任意地位增加和删除元素只须要扭转prev/next指针指向的对象,而不须要挪动元素的地位,所以不会导致迭代器生效。 面试官:list和vector相比,有哪些劣势?什么状况下应用list,什么状况下应用vector? 二师兄:次要有2点劣势:1.list在随机插入数据不会导致数据的搬移。2.list随机删除也不会导致数据搬移。所以在频繁的随机插入/删除的场景应用list,其余场景应用vector。 面试官:你晓得std::sort和list成员函数sort有什么区别吗? 二师兄:std::sort是STL算法的一部分。它排序的容器须要有随机拜访迭代器,所以只能反对vector和deque。list成员函数sort用于list排序,工夫复杂度是O(N*logN)。 面试官:forward_list理解吗?晓得如何实现的吗? 二师兄:std::forward_list是C++11引入的新容器之一。它的底层是单向链表,引入它的次要目标是为了达到手写链表的性能。同时节俭了局部内存空间。(只有一根指针) 面试官:list在pop_front/pop_back的时候须要留神哪些问题? 二师兄:须要判断list的size()不能为0,如果list为空,pop_front/pop_back会导致coredump。 面试官:你晓得list的成员函数insert和forward_list的成员函数的insert_after有什么区别? 二师兄:两者都能够向特定地位增加元素。不同的是insert把元素插入到以后迭代器前,而insert_after把元素插入到以后迭代器后。 面试官:以下代码的输入是什么? #include <iostream>#include <list>int main(int argc, char const *argv[]){ std::list<int> li = {1,2,3,4,5,6}; for(auto it = li.begin(); it!= li.end(); ++it) { if(0 == *it % 2) li.erase(it); } for(auto& i : li) std::cout << i << " "; std::cout << std::endl;}二师兄:应该是1 3 5。 ...

June 24, 2023 · 1 min · jiezi

关于c++:Qt中的dptr与qptr

Qt中的私有类中个别都会蕴含d_ptr这样一个公有类型的指针,指针指向该类对应的公有类,引入这个指针次要是为了解决二进制兼容的问题。 什么是二进制兼容Qt作为一个第三方库,公布后会有很多私有类提供给第三方应用,例如QWidget这类控件类。如果Lib1.0版本中蕴含以下实现。 class Widget { …private: Rect m_geometry;};class Label : public Widget {… String text() const { return m_text; }private: String m_text;};当降级为Lib2.0后,新增了m_stylesheet这样一个成员。 class Widget { …private: Rect m_geometry; String m_stylesheet; // new stylesheet member};class Label : public Widget {public: … String text() const { return m_text; }private: String m_text;};如果第三方利用进行了这样的降级,须要从新编译App,否则会导致解体。究其原因,通过增加了一个新的数据成员,咱们最终扭转了 Widget 和 Label 对象的大小。为什么会这样?因为当你的C++编译器生成代码的时候,他会用偏移量来拜访对象的数据。上面是一个对象在内存外面布局的一个简化版本。| Label对象在 Lib1.0的布局| Label 对象在 Lib2.0的布局 | | m_geometry <偏移量 0> | m_geometry <偏移量 0>| | —————- | m_text <偏移量 1>| | m_stylesheet <偏移量 1> | —————- | | —————- | m_text <偏移量 2>|,在Lib 1.0中,Label的 text 成员在(逻辑)偏移量为1的地位。在编译器生成的代码里,应用程序的办法 Label::text() 被翻译成拜访 Label 对象外面偏移量为1的地位。 在Lib 2.0中,Label 的 text 成员的(逻辑)偏移量被转移到了2的地位!因为应用程序没有从新编译,它依然认为 text 在偏移量1的地位,后果却拜访了stylesheet变量!为什么Label::text()的偏移量的计算的代码会在App二进制文件执行,而不是Lib的二进制文件。 答案是因为Label::text() 的代码定义在头文件外面,最终被内联。 ...

June 24, 2023 · 2 min · jiezi

关于c++:C面试八股文stdvector了解吗

某日二师兄加入XXX科技公司的C++工程师开发岗位第23面: 面试官:vector理解吗? 二师兄:嗯,用过。 面试官:那你晓得vector底层是如何实现的吗? 二师兄:vector底层应用动静数组来存储元素对象,同时应用size和capacity记录以后元素的数量和以后动静数组的容量。如果继续的push_back(emplace_back)元素,当size大于capacity时,须要开拓一块更大的动静数组,并把旧动静数组上的元素搬移到以后动静数组,而后销毁旧的动静数组。 面试官:你晓得新开拓的动静数组的容量是就数组的多少倍比拟适合? 二师兄:这个值在不同的编译器上不是固定的。MSVC 是1.5,而GCC是2。 面试官:有没有什么好的方法晋升vector间断插入效率? 二师兄:有的,如果晓得数据的大略量,咱们能够应用reserve办法间接为vector扩容这个量级。这样在后续的数据插入时就不会因为频繁的capacity被用尽而导致的屡次的数据搬移,从而晋升vector插入效率。 面试官:push_back和emplace_back有什么区别? 二师兄:两者都能够在容器尾部插入元素。在GCC中,如果插入的元素是右值,两者都会move元素到容器。如果是左值,两者都会copy元素到容器。惟一不同的一点是,当C++版本高于C++17时,emplace_back返回以后插入的值的援用,而push_back返回void。 面试官:erase和remove有什么区别? 二师兄:erase属于成员函数,erase删除了元素,remove属于算法库函数,而remove只会把元素挪动到尾部。 面试官:哪些状况下迭代器会生效? 二师兄:迭代器生效次要有两种状况引起:1.插入数据。因为插入数据可能导致数据搬移(size > capacity),所以迭代器生效。2.删除数据。当应用erase删除数据时,被删除数据前面的数据顺次向前移一位。这会导致被删除数据之后的迭代器生效。 面试官:如何疾速的清空vector容器并开释vector容器所占用的内存? 二师兄:有两种办法:第一种,应用clear办法清空所有元素。而后应用shrink_to_fit办法把capacity和size(0)对齐,达到开释内存的作用: #include <iostream>#include <vector>int main(int argc, char const *argv[]){ std::vector<int> vi; vi.reserve(1024); for (int i = 0; i < 1024; i++) vi.push_back(i); std::cout << vi.size() << " " << vi.capacity() << std::endl; //1024 1024 vi.clear(); std::cout << vi.size() << " " << vi.capacity() << std::endl; //0 1024 vi.shrink_to_fit(); std::cout << vi.size() << " " << vi.capacity() << std::endl; //0 0}二师兄:第二种,应用swap办法;#include <iostream>#include <vector>int main(int argc, char const *argv[]){ std::vector<int> vi; vi.reserve(1024); for (int i = 0; i < 1024; i++) vi.push_back(i); std::cout << vi.size() << " " << vi.capacity() << std::endl; //1024 1024 std::vector<int>().swap(vi); //应用长期量(size =0, capacity=0)和vi替换,长期量会立刻析构 std::cout << vi.size() << " " << vi.capacity() << std::endl; //0 0}面试官:你晓得vector<bool>是如何实现的吗? ...

June 23, 2023 · 1 min · jiezi

关于c++:C面试八股文override和finial关键字有什么作用

某日二师兄加入XXX科技公司的C++工程师开发岗位第22面: (二师兄好苦逼,节假日还在面试。。。) 面试官:C++的继承理解吗? 二师兄:(不好意思,你面到我的强项了。。)理解一些。 面试官:什么是虚函数,为什么须要虚函数? 二师兄:虚函数容许在基类中定义一个函数,而后在派生类中进行重写(override)。 二师兄:次要是为了实现面向对象中的三大个性之一多态。多态容许在子类中重写父类的虚函数,同样的函数在子类和父类实现不同的状态,简称为多态。 面试官:你晓得override和finial关键字的作用吗? 二师兄:override关键字通知编译器,这个函数肯定会重写父类的虚函数,如果父类没有这个虚函数,则无奈通过编译。此关键字可省略,但不倡议省略。 二师兄:finial关键字通知编译器,这个函数到此为止,如果后续有类继承以后类,也不能再重写此函数。 二师兄:这两个关键字都是C++11引入的,为了晋升C++面向对象编码的安全性。 面试官:你晓得多态是怎么实现的吗? 二师兄:(起开,我要开始装逼了!)C++次要应用了虚指针和虚表来实现多态。在领有虚函数的对象中,蕴含一个虚指针(virtual pointer)(个别位于对象所在内存的起始地位),这个虚指针指向一个虚表(virtual table),虚表中记录了虚函数的实在地址。 #include <iostream>struct Foo{ size_t a = 42; virtual void fun1() {std::cout <<"Foo::fun1" << std::endl;} virtual void fun2() {std::cout <<"Foo::fun2" << std::endl;} virtual void fun3() {std::cout <<"Foo::fun3" << std::endl;}};struct Goo: Foo{ size_t b = 1024; virtual void fun1() override {std::cout <<"Goo::fun1" << std::endl;} virtual void fun3() override {std::cout <<"Goo::fun3" << std::endl;}};using PF = void(*)();void test(Foo* pf){ size_t* virtual_point = (size_t*)pf; PF* pf1 = (PF*)*virtual_point; PF* pf2 = pf1 + 1; //偏移8字节 到下一个指针 fun2 PF* pf3 = pf1 + 2; //偏移16字节 到下下一个指针 fun3 (*pf1)(); //Foo::fun1 or Goo::fun1 取决于pf的实在类型 (*pf2)(); //Foo::fun2 (*pf3)(); //Foo::fun3 or Goo::fun3 取决于pf的实在类型}int main(int argc, char const *argv[]){ Foo* fp = new Foo; test(fp); fp = new Goo; test(fp); size_t* virtual_point = (size_t*)fp; size_t* ap = virtual_point + 1; size_t* bp = virtual_point + 2; std::cout << *ap << std::endl; //42 std::cout << *bp << std::endl; //1024} ...

June 22, 2023 · 3 min · jiezi

关于c++:C面试八股文用过STL吗

某日二师兄加入XXX科技公司的C++工程师开发岗位第21面: 面试官:用过STL吗? 二师兄:(每天都用好吗。。)用过一些。 面试官:你晓得STL是什么? 二师兄:STL是指规范模板库(Standard Template Library),是C++区别于C语言的特色之一。 面试官:那你晓得STL的六大部件是什么? 二师兄:别离是容器(container)、迭代器(iterator)、适配器(adaptor)、分配器(allocator)、仿函数(functor)和算法(algorithm)。 面试官:那你晓得有哪些容器吗? 二师兄:STL中容器的数量比拟多,依照类型能够分为程序容器和关联容器。 二师兄:程序容器次要有vector、deque、list、forward_list和array。其中forward_list和array是C++11引入的。 二师兄:关联容器次要有set、map、multiset、multimap、unordered_set、unordered_map、unordered_multiset、unordered_multiamp。其中后四种是C++11新引入的。 面试官:好的。那你晓得迭代器分为哪些品种吗? 二师兄:别离是输出迭代器(Input Iterator)、输入迭代器(Output Iterator)、前向迭代器(Forward Iterator)、双向迭代器(Bidirectional Iterator)和随机拜访迭代器(Random Access Iterator)。 二师兄:其中输出和输入迭代器别离用于读取和写入数据,前向迭代器只能向前拜访而不能向后拜访(forward_list),双向迭代器既可向前也可向后(list),随机拜访迭代器能够通过下标拜访任何非法的地位(vector)。 面试官:你晓得适配器是做什么的吗? 二师兄:适配器是一种设计模式。次要起到将不同的接口对立起来的作用。STL中的容器适配器如stack和queue,通过调用容器的接口,实现适配器所需的性能。 面试官:有理解过分配器吗? 二师兄:分配器次要用于内存的调配与开释。个别容器都会自带默认分配器,很少会本人实现分配器。 面试官:有应用分配器做一些内存调配的工作吗? 二师兄:没有。。。 面试官:晓得仿函数是做什么用的吗? 二师兄:是一个可执行的对象,类型重载了operator()()运算符。 struct Add{ int operator()(int a, int b) {return a +b;}}int a = 42, b = 1024;auto sum = Add()(a,b);//ORAdd add;auto sum = add(1,2);面试官:STL中常见的算法有哪些? 二师兄:个别分为三类,查找、排序和数值操作。 二师兄:查找罕用的有std::find、std::find_if、std::find_first_of等。 二师兄:排序次要用std::sort及其家族的一系列算法。 二师兄:数值操作次要用std::accumulate求和。 面试官:那你晓得STL六大部件之间的分割吗? 二师兄:(想了想)不是特地分明。。。 面试官:好的,回去等告诉吧。 让咱们回顾一下二师兄的体现: 有应用分配器做一些内存调配的工作吗?这里次要是问有没有手写过分配器: template <typename T>class MyAllocator {public: typedef T value_type; MyAllocator() noexcept {} template <typename U> MyAllocator(const MyAllocator<U>&) noexcept {} T* allocate(std::size_t n) { if (n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc(); if (auto p = static_cast<T*>(std::malloc(n * sizeof(T)))) return p; throw std::bad_alloc(); } void deallocate(T* p, std::size_t) noexcept { std::free(p); }};实例中定义了一个名为MyAllocator的模板类,它重载了allocate和deallocate运算符用于分配内存和开释内存。示例中malloc和free函数来调配和开释内存,也能够用new和delete。 ...

June 21, 2023 · 1 min · jiezi

关于c++:C面试八股文staticcast了解一下

某日二师兄加入XXX科技公司的C++工程师开发岗位第20面: 面试官:C++中反对哪些类型转换? 二师兄:C++反对C格调的类型转换,并在C++11引入新的关键字标准了类型转换。 二师兄:C++11引入四种新的类型转换,别离是static_cast、dynamic_cast、const_cast、和reinterpret_cast。 二师兄:static_cast用处最宽泛,除了前面三种类型转换外,其余的类型转换都能应用static_cast实现。 二师兄:dynamic_cast次要用于运行时的从父类指针向子类指针转换,如果转换不胜利则返回nullptr。 #include <iostream>struct Base{ virtual void fun() {}};struct Derived : public Base{ virtual void fun() override {}};int main(int argc, char const *argv[]){ Base* b1 = new Base; Base* b2 = new Derived; Derived* d1 = dynamic_cast<Derived*>(b1); //d1 == nullptr Derived* d2 = dynamic_cast<Derived*>(b2); //d2 != nullptr}二师兄:const_cast次要用于去除指针或援用类型的const属性。此操作可能会导致未定义的行为,所以须要慎用。#include <iostream>void function(const int& val){ int& v = const_cast<int&>(val); v = 42;}int main(int argc, char const *argv[]){ int val = 1024; function(val); std::cout << val << std::endl; //val == 42}//-----------------------------------------------#include <iostream>static constexpr int val_static = 1024;void function(const int& val){ int& v = const_cast<int&>(val); v = 42;}int main(int argc, char const *argv[]){ function(val_static); std::cout << val_static << std::endl;}// Segmentation fault二师兄:reinterpret_cast能够将指针或援用转换为任何类型的指针或援用。reinterpret_cast实现依赖于编译器和硬件,可能导致未定义的行为。#include <iostream>int main(int argc, char const *argv[]){ int i = 42; double d = 42.0; long* l1 = reinterpret_cast<long*>(&i); long* l2 = reinterpret_cast<long*>(&d); std::cout << *l1 << std::endl; //*i1 == 42 std::cout << *l2 << std::endl; //*i2 == 4631107791820423168 X86_64 GCC 11.3 }面试官:好的。既然曾经有C格调的类型转换,C++11为什么还要引入新的类型转换关键字? ...

June 20, 2023 · 2 min · jiezi

关于c++:适用于-Visual-Studio-的-C-万能头持续更新版VS-万能头

用于在 Visual Studio 上预编译的 C++ 蕴含(stdc++.h for VS v1.0.0)此文件是 GCC 13.1.0 中 <bits/stdc++.h> 文件的批改版本,与 Visual Studio 兼容。批改由 Xi Xu 实现,他的集体官方主页是 https://xi-xu-zg.github.io/。批改版本是依据 GNU General Public License v3.0 or later 散发的。原始文件是依据 GNU General Public License v3.0 or later 散发的。您能够在 https://gcc.gnu.org/onlinedocs/gcc-13.1.0/libstdc++/api/a00839_source.html 找到原始文件。// C++ includes used for precompiling on Visual Studio// Copyright (c) 2023 Xi Xu// SPDX-License-Identifier: GPL-3.0-or-later// This file is a modified version of the <bits/stdc++.h> file from GCC 13.1.0 that is compatible with Visual Studio.// The modifications are made by Xi Xu whose personal official home page is https://xi-xu-zg.github.io/.// The original file is distributed under the GNU General Public License v3.0 or later.// You can find the original file at https://gcc.gnu.org/onlinedocs/gcc-13.1.0/libstdc++/api/a00839_source.html.// 17.4.1.2 Headers#pragma once// C#include <cassert>#include <cctype>#include <cfloat>#include <ciso646>#include <climits>#include <csetjmp>#include <cstdarg>#include <cstddef>#include <cstdlib>#include <cstdint>// C++// #include <bitset>// #include <complex>#include <algorithm>#include <bitset>#include <functional>#include <iterator>#include <limits>#include <memory>#include <new>#include <numeric>#include <typeinfo>#include <utility>#include <array>#include <atomic>#include <initializer_list>#include <ratio>#include <scoped_allocator>#include <tuple>#include <typeindex>#include <type_traits>#if _HAS_CXX17#include <any>// #include <execution>#include <optional>#include <variant>#include <string_view>#endif#if _HAS_CXX20#include <bit>#include <compare>#include <concepts>#include <numbers>#include <ranges>#include <span>#include <source_location>#include <version>#endif#if _HAS_CXX23#include <expected>#include <stdatomic.h>#if __cpp_impl_coroutine#include <coroutine>#endif#endif// C#include <cassert>#include <cctype>#include <cerrno>#include <cfloat>#include <ciso646>#include <climits>#include <clocale>#include <cmath>#include <csetjmp>#include <csignal>#include <cstdarg>#include <cstddef>#include <cstdio>#include <cstdlib>#include <cstring>#include <ctime>#include <cwchar>#include <cwctype>#include <ccomplex>#include <cfenv>#include <cinttypes>#include <cstdalign>#include <cstdbool>#include <cstdint>#include <ctgmath>#include <cuchar>// C++#include <complex>#include <deque>#include <exception>#include <fstream>#include <functional>#include <iomanip>#include <ios>#include <iosfwd>#include <iostream>#include <istream>#include <iterator>#include <limits>#include <list>#include <locale>#include <map>#include <memory>#include <new>#include <numeric>#include <ostream>#include <queue>#include <set>#include <sstream>#include <stack>#include <stdexcept>#include <streambuf>#include <string>#include <typeinfo>#include <utility>#include <valarray>#include <vector>#include <array>#include <atomic>#include <chrono>#include <codecvt>#include <condition_variable>#include <forward_list>#include <future>#include <initializer_list>#include <mutex>#include <random>#include <ratio>#include <regex>#include <scoped_allocator>#include <system_error>#include <thread>#include <tuple>#include <typeindex>#include <type_traits>#include <unordered_map>#include <unordered_set>#include <shared_mutex>#if _HAS_CXX17#include <any>#include <charconv>// #include <execution>#include <filesystem>#include <optional>#include <memory_resource>#include <variant>#endif#if _HAS_CXX20#include <barrier>#include <bit>#include <compare>#include <concepts>#include <format>#include <latch>#include <numbers>#include <ranges>#include <span>#include <stop_token>#include <semaphore>#include <source_location>#include <syncstream>#include <version>#endif#if _HAS_CXX23#include <expected>#include <spanstream>#if __has_include(<stacktrace>)#include <stacktrace>#endif#include <stdatomic.h>#include <stdfloat>#endifGit 仓库 GitHub Gitee ...

June 20, 2023 · 2 min · jiezi

关于c++:C面试八股文什么是智能指针

某日二师兄加入XXX科技公司的C++工程师开发岗位第19面: 面试官:什么是智能指针? 二师兄:智能指针是C++11引入的类模板,用于治理资源,行为相似于指针,但不须要手动申请、开释资源,所以称为智能指针。 面试官:C++11引入了哪些智能指针? 二师兄:三种,别离是shared_ptr、unique_ptr、和weak_ptr。 面试官:说一说三种指针的特色及用处。 二师兄:好的。shared_ptr应用了援用计数(use count)技术,当复制个shared_ptr对象时,被治理的资源并没有被复制,而是减少了援用计数。当析构一个shared_ptr对象时,也不会间接开释被治理的的资源,而是将援用计数减一。当援用计数为0时,才会真正的开释资源。shared_ptr能够不便的共享资源而不用创立多个资源。 二师兄:unique_ptr则不同。unique_ptr独占资源,不能拷贝,只能挪动。挪动过后的unique_ptr实例不再占有资源。当unique_ptr被析构时,会开释所持有的资源。 二师兄:weak_ptr能够解决shared_ptr所持有的资源循环援用问题。weak_ptr在指向shared_ptr时,并不会减少shared_ptr的援用计数。所以weak_ptr并不知道shared_ptr所持有的资源是否曾经被开释。这就要求在应用weak_ptr获取shared_ptr时须要判断shared_ptr是否无效。struct Boo;struct Foo{ std::shared_ptr<Boo> boo;};struct Boo{ std::shared_ptr<Foo> foo;};二师兄:Foo中有一个智能指针指向Goo,而Goo中也有一根智能指针指向Foo,这就是循环援用,咱们能够应用weak_ptr来解决这个文通。Boo boo;auto foo = boo.foo.lock();if(foo){ //这里通过获取到了foo,能够应用}else{ //这里没有获取到,不能应用}面试官:好的。智能指针是线程平安的吗? 二师兄:是的。抛开类型T,智能指针是类型平安的。 面试官:为什么? 二师兄:因为智能指针底层应用的援用计数是atomic的原子变量,原子变量在自增自减时是线程平安的,这保障了多线程读写智能指针时是平安的。 面试官:好的。为什么尽量不要应用裸指针初始化智能指针? 二师兄:因为可能存在同一个裸指针初始了多个智能指针,在智能指针析构时会造成资源的屡次开释。 面试官:为什么不要从智能指针中返回裸指针呢? 二师兄:是因为如果返回的裸指针被开释了,智能指针持有的资源也生效了,对智能指针的操作是未定义的行为。 面试官:智能指针可能持有数组吗? 二师兄:shread_ptr和unique_ptr都能够持有数组。 面试官:那你晓得在开释资源的时候两者有什么不同吗? 二师兄:这个临时还不分明。。 面试官:能够应用动态对象初始化智能指针吗? 二师兄:让我想想。。不能够,因为动态对象的生命周期和过程一样长,而智能指针的析构的时候会导致动态资源被开释。这会导致未定义的行为。 面试官:如果须要在一个类中实现一个办法,这个办法返回这个类的shread_ptr实例,须要留神哪些货色? 二师兄:须要继承std::enable_shared_from_this类,办法返回shared_from_this()。 struct Foo : public std::enable_shared_from_this<Foo>{ std::shared_ptr<Foo> get_foo() { return shared_from_this(); }};面试官:为什么不间接返回this指针? 二师兄:额。。。不太分明,然而这应该是个范式。 面试官:好的,明天的面试完结了,请回去等告诉吧。 明天二师兄的体现不错,让咱们看看一些答复的不太现实的中央吧。 智能指针是线程平安的吗?很遗憾,使用不当的时候并不是。 #include <iostream>#include <memory>#include <thread>#include <chrono>struct Foo{ Foo(int i):i_(i){} void print() {std::cout << i_ << std::endl;} int i_;};int main(int argc, char const *argv[]){ { auto shptr = std::make_shared<Foo>(42); std::thread([&shptr](){ std::this_thread::sleep_for(std::chrono::seconds(1)); shptr->print(); }).detach(); } std::this_thread::sleep_for(std::chrono::seconds(2)); return 0;}// g++ test.cpp -o test -lpthread// ./test // Segmentation fault当咱们向另一个线程传递智能指针的援用时,因为use count并没有加1,在shptr析构时间接销毁了治理的Foo实例,所以在线程中执行shptr->print()会引发coredump。 ...

June 19, 2023 · 1 min · jiezi

关于c:c语言大作业基于多种加密技术与防护措施的c语言安全笔记本程序设计与实现

作业: 为了保障用户的本地笔记数据安全,决定构建了一个安全可靠的加密笔记本程序,利用了多种加密技术和防护措施,确保用户数据不受未经受权的用户拜访或获取。这个加密笔记本领有以下技术特点: 1.加密数据 为了保障用户笔记的安全性和保密性,咱们应用AES加密算法对数据进行加密。AES(Advanced Encryption Standard)是一种高级加密规范,已被广泛应用于商业和政府畛域。相比于其余算法,AES算法更加安全可靠,能够提供更高的数据安全性。在加密笔记本中,咱们采纳了AES-256-CBC算法,提供了更高的安全性。同时,咱们还应用随机生成的初始化向量(IV),进一步加强了加密算法的安全性。 2.明码哈希 为了防止用户明码被其他人获取或窃取,咱们应用bcrypt明码哈希算法对用户明码进行加密。bcrypt是一种比MD5和SHA-1等哈希算法更加平安和牢靠的明码哈希算法,可能提供更高的密码保护。在加密笔记本中,咱们将用户输出明码进行bcrypt哈希,而后再保留到数据库中。这样,即便黑客获取到了加密笔记本的数据库,也无奈轻易地取得明文明码。 3.防重放攻打 防重放攻打是一种黑客攻击形式,攻击者会利用已知的数据包重放来达到攻打的目标。在加密笔记本中,咱们引入了随机数和工夫戳,以避免重放攻打。每个申请都会生成一个惟一的随机数和工夫戳,并与其余申请进行辨别。这样,黑客就无奈在短时间内重放申请,从而保障了应用程序的安全性。 4.严格的输出验证 因为用户输出谬误或歹意攻打是导致应用程序呈现问题的次要起因之一,因而咱们在加密笔记本中退出了对用户名和明码的字符长度和复杂度等方面的严格验证,保障了输出的正确性和安全性。如果用户输出不符合规范,应用程序就会提醒用户从新输出。 #include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include <openssl/evp.h>#include <openssl/rand.h>#include <openssl/bcrypt.h>#define MAX_NOTES 100void encrypt(const unsigned char *input, int input_len, unsigned char *key, unsigned char *iv, unsigned char *output) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); int output_len; EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); EVP_EncryptUpdate(ctx, output, &output_len, input, input_len); EVP_EncryptFinal_ex(ctx, output + output_len, &output_len); EVP_CIPHER_CTX_free(ctx);}void decrypt(const unsigned char *input, int input_len, unsigned char *key, unsigned char *iv, unsigned char *output) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); int output_len; EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); EVP_DecryptUpdate(ctx, output, &output_len, input, input_len); EVP_DecryptFinal_ex(ctx, output + output_len, &output_len); EVP_CIPHER_CTX_free(ctx);}// 验证明码复杂度(至多蕴含 8 个字符,其中必须包含数字、大写字母、小写字母和特殊字符)bool check_password(const char* password) { int password_len = strlen(password); if (password_len < 8) { return false; } bool has_digit = false; bool has_upper = false; bool has_lower = false; bool has_special = false; for (int i = 0; i < password_len; i++) { if (isdigit(password[i])) { has_digit = true; } else if (isupper(password[i])) { has_upper = true; } else if (islower(password[i])) { has_lower = true; } else { has_special = true; } } if (!has_digit || !has_upper || !has_lower || !has_special) { return false; } return true;}// 验证用户名和明码是否匹配bool check_user(const char* username, const char* password) { // 增加自定义的用户名和明码认证逻辑代码 return true;}// 加载并解密笔记数据bool load_notes(const char* filename, unsigned char* key, unsigned char* iv, unsigned char* notes_buf, int notes_buf_len) { FILE* fp = fopen(filename, "rb"); if (fp == NULL) { printf("Note file not found or unable to open.\n"); return false; } fseek(fp, 0, SEEK_END); int file_size = ftell(fp); rewind(fp); if (file_size > notes_buf_len) { printf("Notes buffer size is too small. %d bytes are required.\n", file_size); fclose(fp); return false; } unsigned char* encrypted_notes = malloc(file_size); fread(encrypted_notes, 1, file_size, fp); fclose(fp); decrypt(encrypted_notes, file_size, key, iv, notes_buf); free(encrypted_notes); return true;}// 保留并加密新笔记数据bool save_notes(const char* filename, unsigned char* key, unsigned char* iv, unsigned char* notes_buf, int notes_len) { unsigned char* encrypted_notes = malloc(notes_len); encrypt(notes_buf, notes_len, key, iv, encrypted_notes); FILE* fp = fopen(filename, "wb"); if (fp == NULL) { printf("Unable to open file for writing.\n"); free(encrypted_notes); return false; } if (fwrite(encrypted_notes, 1, notes_len, fp) != notes_len) { printf("Unable to write notes data to file.\n"); fclose(fp); free(encrypted_notes); return false; } fclose(fp); free(encrypted_notes); return true;}int main() { char username[80]; char password[80]; // 输出验证 while(true) { printf("Please enter your username: "); scanf("%s", username); printf("Please enter a strong password (at least 8 characters with numbers, uppercase/lowercase letters, and special characters): "); scanf("%s", password); if (!check_password(password)) { printf("Password does not meet complexity requirements. Please try again.\n"); continue; } if (!check_user(username, password)) { printf("Invalid username or password. Please try again.\n"); continue; } break; } // 随机数和工夫戳,用于防重放攻打 int timestamp = time(NULL); RAND_add(&timestamp, sizeof(timestamp)); unsigned char nonce[8]; RAND_bytes(nonce, sizeof(nonce)); // 加载并解密笔记数据 unsigned char iv[EVP_MAX_IV_LENGTH]; memset(iv, 0x00, EVP_MAX_IV_LENGTH); unsigned char* notes_buf = malloc(MAX_NOTES); unsigned char salt[BCRYPT_SALTSPACE]; RAND_bytes(salt, sizeof(salt)); unsigned char* hash = malloc(BCRYPT_HASHSPACE); bcrypt(password, strlen(password), salt, hash, BCRYPT_HASHSPACE); if (!load_notes("notes.enc", hash, iv, notes_buf, MAX_NOTES)) { free(notes_buf); return 1; } // 显示笔记 printf("%s\n", notes_buf); // 输出新笔记 printf("Enter new notes:\n"); char new_notes[MAX_NOTES]; fgets(new_notes, MAX_NOTES, stdin); // 保留并加密新笔记数据 int new_notes_len = strlen(new_notes); if (!save_notes("notes.enc", hash, iv, (unsigned char*)new_notes, new_notes_len)) { free(notes_buf); return 1; } free(notes_buf); free(hash); return 0;}

June 19, 2023 · 3 min · jiezi

关于c++:C面试八股文stdstring是如何实现的

某日二师兄加入XXX科技公司的C++工程师开发岗位第18面: 面试官:std::string用过吧? 二师兄:当然用过(废话,C++程序员就没有没用过std::string的)。 面试官:std::string("hello")+"world"、"hello"+std::string("world")和std::string("hello")+std::string("world")的后果是什么?为什么? 二师兄:前者和后者的后果都是std::string的对象,内容是“helloworld\0”,而两头的这个表达式无奈通过编译。起因是std::string重载了operator+(const char*)和operator+(const std::string&),然而const char* 却没有重载operator+运算符。 面试官:std::string 有两个API,resize和reserve,你晓得它们之间的区别吗? 二师兄:resize对应的是size,resize能够扭转字符串的大小。reserve对应的是capacity,reserve只能扭转capacity的大小。 二师兄:当resize传入的参数小于字符串的szie时,多余的字符串会被截取。当reserve传入的参数小于capacity时,reserve什么也不会做。 二师兄:当resize传入的参数大于字符串的szie时,减少的字符串会被默认初始化。当reserve传入的参数大于capacity时,capacity会被扩容。 面试官:好的。能够通过下标拜访std::string实例的内容吗? 二师兄:能够的,std::string重载了下标运算符,能够像数组一样通过下标运算取出某个字符。 面试官:你晓得std::string的at成员办法吗? 二师兄: 嗯,和下标运算性能类似,不过不必放心越界问题。能够平安的拜访字符串中的字符。 面试官:既然有at办法了,为什么还要重载下标运算符呢? 二师兄:次要是因为性能上的考量。at尽管保障了不会超出字符串范畴(超出范围抛出异样),然而性能低于下标操作。这就是有舍有得。为了平安应用at,为了性能应用下标操作。C++给了你多个抉择,如何抉择看你的需要。 面试官:那你晓得std::string是如何实现的吗? 二师兄:在string外部保护一个指针,这个指针指向真正的字符串的地位。 面试官:能简略的写一下实现代码吗? 二师兄:好的。 class string{public: string():size_(0),data_(nullptr){} explicit string(const char* c) { size_ = strlen(c); data_ = (char*)malloc(size_+1); memset(data_,0,size_+1); memcpy(data_,c,size_); } size_t size() const {return size_;} const char* c_str() const {return data_;}private: size_t size_; char* data_;};二师兄:在实现append或者+=的时候,须要把以后字符的长度加上append的内容的长度,以此长度申请一块新内存,而后把以后字符串的内存和append 的内容考入新申请的内存中。free掉之前data_指向的内存,而后把data_指针指向新申请的内存。 面试官:好的。这样的实现有一些弊病。如果频繁的对一个std::string对象append内容,会产生什么? 二师兄:是的,因为频繁的malloc和free,会有性能问题。因所以编译器在实现std::string的时候个别会事后申请一块大的内存,这块内存的长度是capacity,当增加的字符串的长度加上以后的字符串长度小于capacity时,间接增加到以后的块上即可。 面试官:好的。针对字符串比拟少的状况,个别编译器会做一些优化,你晓得如何优化的吗? 二师兄:这个如同在哪看过,不记得额。。。 面试官:好的,明天的面试完结了,请回去等告诉吧。 明天二师兄的体现不错,除了最初一个问题,基本上都答上来了。让咱们来看下这个问题: 针对字符串比拟少的状况,个别编译器会做一些优化,你晓得如何优化的吗?咱们能够看看GCC中std::string的实现: typedef basic_string<char> string; _Alloc_hider _M_dataplus;size_type _M_string_length;enum { _S_local_capacity = 15 / sizeof(_CharT) };union{ _CharT _M_local_buf[_S_local_capacity + 1]; size_type _M_allocated_capacity;};这里的_CharT就是char,所以_S_local_capacity等于15。当字符串的长度小于等于15时,间接存在_M_local_buf中,而不须要在堆中申请内存。当字符串长度大于15时,在内存中申请一块内存,这块内存的起始地址保留在_M_dataplus中,这块内存的容量保留在_M_allocated_capacity 中,而字符串的实在长度保留在_M_string_length中。当向字符串中增加字符时,如果增加字符的长度大于 _M_allocated_capacity - _M_string_length,则须要resize,否则间接追加到_M_dataplus保留的内存块中即可。 ...

June 18, 2023 · 1 min · jiezi

关于c++:C面试八股文聊一聊指针

某日二师兄加入XXX科技公司的C++工程师开发岗位第17面: 面试官:聊一聊指针? 二师兄:好的。 面试官:你感觉指针实质上是什么? 二师兄:这要从内存地址开始说起了。如果有一块容量是1G的内存,假如它的地址是从0x00000000 到0x3fffffff,每一个字节都对应一个地址。当咱们申明一个变量并初始化它时: int a = 42;二师兄:操作系统会调配一块容量为4(sizeof(int))的地址,这块内存的首地址是0x00001000(假如),完结地址是0x00001003,在申请的这4个字节上放入42。当咱们对这个变量取地址时,int a = 42;int* p = &a;二师兄:操作系统会再调配一块内存,这块内存的大小是sizeof(int*),这块内存的起始地址是0x00002000(假如),完结地址是0x00002003(32位操作系统),而后将&a取到的起始地址0x00001000放入0x00002000-0x00002003中。并将刚调配的这块内存的起始地址赋给p。 二师兄:当咱们对p操作时,是对0x00002000-0x00002003这块内存操作,当咱们对*p(解援用)操作时,是对0x00001000-0x00001003这块内存操作。 二师兄:回到问题,我感觉指针的实质就是内存地址。尽管指针指向一块内存地址,但它同时也是一个变量,也能够对指针取地址。如果对指针取地址,同样能够失去一个内存地址(如0x00002000),如果把这个内存地址存起来,那么指向这个内存地址的变量的类型就是二级指针(int**)。 面试官:好的。在0x00002000-0x00002003这块内存中,咱们放入了一个地址是0x00001000,然而并没有这个地址的长度。只晓得一个地址而不晓得长度,怎么能把数据取出来? 二师兄:这次要是因为p的类型是int*,当对p解援用时,编译器晓得理解援用的后果是int类型,所以从0x00001000往后读取4个字节(sizeof(int)),并依照以后CPU的模式(思考大小端)把这四个字节组成一个int类型的变量。 面试官:malloc函数你晓得吧,返回的类型是void*,在free的时候怎么晓得这块内存的大小的呢? 二师兄:额。。这个还不太分明。。 面试官:没关系,明天就到这里,回去等告诉吧。 让咱们来看看让二师兄折戟的这个问题: malloc函数返回的类型是void*,在free的时候怎么晓得这块内存的大小的呢?这里牵扯到malloc和free的实现形式,不同的厂商实现的形式不尽相同。以ptmalloc为例,当应用malloc申请size = 16的内存时,malloc会从内存池中调配一块sizeof(chunk)+16长度的内存。chunk段保留了一些前后chunk的信息,也保留了这块内存的大小(16)。malloc函数返回的地址是0x00001000,而在free(0x00001000)时,free函数会用0x00001000减去特定值(sizeof(chunk)),失去chunk的起始地址,从chunk中获取这块内存真正的尺寸,从而实现free的工作。抛开内存的利用率不说,这是一个十分美好的实现! ![]() 好了,今日份面试到这里就完结了。关注我,每天带你学习一个C++小常识! 关注我,带你21天“精通”C++!(狗头)

June 17, 2023 · 1 min · jiezi

关于c++:C面试八股文什么是左值什么是右值

某日二师兄加入XXX科技公司的C++工程师开发岗位第16面: 面试官:什么是左值,什么是右值? 二师兄:简略来说,左值就是能够应用&符号取地址的值,而右值个别不能够应用&符号取地址。 int a = 42; //a是左值,能够&aint* p = &a;int* p = &42; //42是右值,无奈取地址二师兄:个别左值存在内存中,而右值存在寄存器中。int a = 42, b = 1024;decltype(a+b); //类型为右值,a+b返回的值存在寄存器中decltype(a+=b); //类型为左值,a+=b返回的值存储在内存中二师兄:严格意义上分,右值分为纯右值(pvalue)和将亡值(xvalue)。C++中,除了右值残余的就是左值。42; //纯右值int a = 1024;std::move(a); //将亡值面试官:C++98/03中曾经有了左值,为什么还要减少右值的概念? 二师兄:次要是为了效率。特地是STL中的容器,当须要把容器当作参数传入函数时: void function(std::vector<int> vi2){ vi2.push_back(6); for(auto& i: vi2) { std:: cout < i << " " ;} std::cout << std::endl;}int main(int argc, char* argv[]){ std::vector<int> vi1{1,2,3,4,5}; function(vi1); return 0;}二师兄:当咱们要把vi1传入函数时,在C++98/03时只能通过拷贝构造函数,把vi1中所有的元素全副拷贝一份给vi2,拷贝实现之后,当function函数返回时,vi2被析构,而后vi1被析构。 二师兄:在C++11及之后,咱们能够通过std::move()把vi1强制转为右值,此时在初始化vi2时执行的不是拷贝结构而是挪动结构: void function(std::vector<int>&& vi2){ vi2.push_back(6); for(auto& i: vi2) { std:: cout < i << " " ;} std::cout << std::endl;}int main(int argc, char* argv[]){ std::vector<int> vi1{1,2,3,4,5}; function(std::move(vi1)); return 0;}二师兄:这里只进行了一次结构。一次挪动(当元素特地多时,挪动的老本绝对于拷贝根本能够疏忽不记),一次析构。效率失去很大的晋升。 ...

June 16, 2023 · 2 min · jiezi

关于c#:CVBNET快速而简单的免费SVG到PDF转换技巧

在日常工作中,咱们经常须要将SVG转换为PDF格局。这是因为SVG格局的图像在打印时可能会呈现问题,例如失去分辨率或无奈正确适应纸张大小。与此相比,PDF格局则专门用于打印和共享文档,能够确保高质量输入,并且可能主动适应不同的纸张大小。在本文中,咱们将介绍如何应用编程形式将SVG文件转换为PDF,并以C#代码示例演示该过程。一起学起来吧! 1. 筹备工作办法1:将Free Spire.PDF for .NET 下载到本地,解压,找到 BIN 文件夹下的 Spire.PDF.dll。而后在 Visual Studio 中关上“解决方案资源管理器”,鼠标右键点击“援用”,“增加援用”,将本地门路 BIN 文件夹下的 dll 文件增加援用至程序。办法2::通过NuGet装置。可通过以下 2 种办法装置: 能够在 Visual Studio 中关上“解决方案资源管理器”,鼠标右键点击“援用”,“治理 NuGet 包”,而后搜寻“Free Spire.PDF”,点击“装置”。期待程序安装实现。将以下内容复制到 PM 控制台装置。Install-Package FreeSpire.PDF -Version 8.6.0 具体步骤依照下列操作,仅需三步即可实现对SVG文件的转换。 创立PdfDocument对象。应用PdfDocument.LoadFromFile() 办法加载一个示例SVG文件。应用PdfDocument.SaveToFile(String, FileFormat) 办法将SVG文件转换为PDF。 残缺代码C# using Spire.Pdf;namespace SVGtoPDF{ class Program { static void Main(string[] args) { //创立PdfDocument对象 PdfDocument doc = new PdfDocument(); //加载一个示例SVG文件 doc.LoadFromSvg("Sample.svg"); //保留后果文档 doc.SaveToFile("Result.pdf", FileFormat.PDF); doc.Dispose(); } }}VB.NET Imports Spire.PdfNamespace SVGtoPDF Friend Class Program Private Shared Sub Main(ByVal args As String()) '创立PdfDocument对象 Dim doc As PdfDocument = New PdfDocument() '加载一个示例SVG文件 doc.LoadFromSvg("Sample.svg") '保留后果文档 doc.SaveToFile("Result.pdf", FileFormat.PDF) doc.Dispose() End Sub End ClassEnd Namespace效果图 ...

June 16, 2023 · 1 min · jiezi

关于c++:C面试八股文了解auto关键字吗

某日二师兄加入XXX科技公司的C++工程师开发岗位第15面: 面试官:理解auto关键字吗? 二师兄:嗯,理解一些(我很相熟)。 面试官:说一说auto的用法吧? 二师兄:auto次要是为了编译器进行类型推导。比方: auto i = 42; //i 被推导位int型std::vector<int> vi;for(auto it = vi.cbegin(); it != vi.cend(); ++it){ std::cout << *it << std::endl;} //迭代器的类型又臭又长auto l_fun = [](int a, int b){return a+b;} //lambda的类型基本上不可能手写进去二师兄:也能够作为函数返回类型的占位符:auto add(int a, int b)->(decltype(a+b)){ return a + b;} //C++11auto add(int a, int b){ return a + b;} //C++14及当前二师兄:在C++20中还能够推导参数的类型,从而实现相似模板的成果:auto add(auto a,auto b){ return a+b;} //C++20 此时能够这样应用 auto res = add(std::string("hello"),"world");//相似以下成果,不过下面的写法更简洁template<typename T,typename U>auto add(T&& t, U&& u)->decltype(t+u){ return t + u;}面试官:嗯,不错。你感觉auto有哪些益处? ...

June 15, 2023 · 1 min · jiezi