关于c++:LX-COG-12864R1-LCD-Sample-Code

IntroductionSample code for driving LX COG 12864R1 LCD. NOTE For arudino only.But it's very easy to apply on STM.To run the code, you'd better to have a Arduino Mega 2560 which can print the log.Code// The .ino file.// Define PINs#define CS 2#define RST 3#define DC 4#define SCL 21#define SDA 20#define setPin(pin, x) digitalWrite(pin, (x) ? HIGH : LOW)#define cs(x) setPin(CS, (x))#define reset(x) setPin(RST, (x))#define dc(x) setPin(DC, (x))#define scl(x) setPin(SCL, (x))#define sda(x) setPin(SDA, (x))void log(const char* str) { Serial.println(str);}void spi_delay(uint16_t x) { while(x > 0) { x--; }}void spi_send(uint8_t val) { for(int i = 0; i < 8; i++) { if (val & 0x80) { sda(1); } else { sda(0); } spi_delay(1); scl(1); scl(0); val <<= 1; }}void lcd_cmd(uint8_t val) { cs(0); dc(0); spi_send(val); cs(1); dc(1);}void lcd_data(uint8_t val) { cs(0); dc(1); spi_send(val); cs(1); dc(1);}void lcd_init() { log("Reset 1"); reset(1); delay(1000); log("Reset 2"); reset(0); delay(1000); log("Reset 3"); reset(1); delay(1000); log("Reset internal"); lcd_cmd(0xe2); // Internal reset lcd_cmd(0xe3); // reset signal // delay(3000); log("Display off"); lcd_cmd(0xae); // display off // delay(3000); log("ADC select"); lcd_cmd(0xa0); // ADC select lcd_cmd(0xc8); // command output select lcd_cmd(0x2f); // power control // delay(3000); // SET dir // log("Set direction"); // log("Reversed"); lcd_cmd(0xa1); //0b10100001); // Reverse // log("Normal"); lcd_cmd(0xa0); // 0b10100000); // Normal // delay(3000); log("Inverse display"); // Inverse display // log("Reversed"); lcd_cmd(0xa7); // 0b10100111); // Reverse // log("No"); lcd_cmd(0xa6); // 0b10100110); // Normal // delay(3000); log("All pixels on"); // // All pixels on // lcd_cmd(0xa5); // 0b10100101); // All on // lcd_cmd(0xa4); // 0b10100100); // Normal // delay(3000); log("Set bias"); // bias log("1/9 bias"); lcd_cmd(0xa2); //(0xa2 1/9 bias,1/65 duty ) // log("1/7 bias"); lcd_cmd(0xa3); // 1/7 // delay(3000); // log("Page blink"); // // Page Blink Page // lcd_cmd(0xd5); // lcd_cmd(0x0); // Blink all page: 0xF // delay(3000); // Ratio is a key parameter which haverily affects the invisibility. log("Select resistor ratio"); // select resistor ratio Rb/Ra: 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 lcd_cmd(0x22); // delay(3000); log("Select volume"); lcd_cmd(0x81); // select volume // delay(3000); log("vop"); lcd_cmd(0x29); // 0x15); //0x29); // vop // delay(3000); lcd_cmd(0xf8); // x4 lcd_cmd(0x08); // x4 // delay(3000); log("Initial page"); lcd_cmd(0xb0);//set page address lcd_cmd(0x10);//set column address lcd_cmd(0x00); for(int col=0; col < 128; col++) { lcd_data(0x00); // lcd_data(0b11110000); } // delay(3000); log("Display on"); lcd_cmd(0xaf); //display on // delay(3000);}uint8_t img[] = { 0xFF,0x01,0x01,0x01,0x01,0x01,0x09,0x09,0xFD,0xFD,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFF};void lcd_display() { uint8_t* ptr = img; for(int row = 0xb0; row < 0xb8; row++) { lcd_cmd(row); lcd_cmd(0x10); lcd_cmd(0x00); for(int col = 0; col < 128; col++) { lcd_data(*ptr++); } } delay(2000);}void lcd_clean(uint8_t color = 0x00) { for(int row = 0xb0; row < 0xb8; row++) { lcd_cmd(row); lcd_cmd(0x10); lcd_cmd(0x00); for(int col = 0; col < 128; col++) { // lcd_data(0x81); // lcd_data(0x81); lcd_data(color); } } // delay(1000);}void setup() { // put your setup code here, to run once: pinMode(CS, OUTPUT); pinMode(RST, OUTPUT); pinMode(DC, OUTPUT); pinMode(SCL, OUTPUT); pinMode(SDA, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600);}void loop() { // put your main code here, to run repeatedly: lcd_init(); uint8_t color = 0x00; while(1) { // delay(1500); digitalWrite(LED_BUILTIN, HIGH); log("Clean"); lcd_clean(color++); // if (color == 0xFE) color = 0x00; log("Display"); lcd_display(); // reset(0); delay(100); // lcd_display(); digitalWrite(LED_BUILTIN, LOW); // reset(1); delay(100); }}Good Luck!

February 12, 2021 · 3 min · jiezi

关于c++:Need-For-Speed-Nodejs-Module-In-C

IntroductionThe reason can't be more simple: the need for speed. According to a simple test between node-uuid and C++ uuid, the truth was told: C++ is faster. The time consumptions of 1M generations of uuid is almost 3s(node-uuid) vs. 0.3s(C++ modules based on boost uuid). So, the advices is: crucial module should be written in C++, if you have time for this. node-uuid Module in C++node-uuid.h#ifndef NODE_UUID_H#define NODE_UUID_Husing namespace v8;#define NODE_UUID_CLS_NAME "nodeUuid"namespace igame{ namespace uuid { void initialize(Handle<Object> exports); }} // ns#endifnode-uuid.cpp#include "node_uuid.hpp"// #include <boost/lexical_cast.hpp>namespace igame{ namespace uuid { Persistent<Function> constructor; buid::random_generator uuid_generator; uint32_t uuid_count; Handle<Value> generate_uuid(const Arguments& args); Handle<Value> get_count(Local<String> property, const AccessorInfo& info); void initialize(Handle<Object> exports) { exports->Set(String::NewSymbol("next"), FunctionTemplate::New(generate_uuid)->GetFunction()); exports->SetAccessor(String::NewSymbol("count"), get_count, NULL); } Handle<Value> generate_uuid(const Arguments& args) { HandleScope scope; buid::uuid uid = uuid_generator(); uuid_count++; return scope.Close(String::New(buid::to_string(uid).c_str())); } Handle<Value> get_count(Local<String> property, const AccessorInfo& info) { HandleScope scope; return scope.Close(Integer::New(uuid_count)); } } // ns} // nsTesttest.js ...

February 12, 2021 · 1 min · jiezi

关于c++:C-Style-IO-Access-For-STM32

IntroductionFor STM, the common ways to manipulate low hardware are HAL and memory/register access. For third-party hardwares, there are no HAL support and we have to do memory/register access. For example, for ili9341 TFT LCD, the driving code looks like the following: // Define the memory model for IO/Register access.typedef struct { __IO uint16_t reg; __IO uint16_t mem;} LCD_TypeDef;#define LCD_BASE ((uint32_t)(0x6C000000 | 0x000007FE))#define LCD ((LCD_TypeDef *)LCD_BASE)// Write commands by assignment.// NOTE: If people know some about FPGA will// figure out that they are much similar.INLINE void lcd_cmd(uint16_t cmd) { LCD->reg = cmd;}// Write data by assignment.INLINE void lcd_data(uint16_t dat) { LCD->mem = dat;}INLINE void lcd_cmd_data(uint16_t cmd, uint16_t data) { LCD->reg = cmd; LCD->mem = data;}Personally, I prefer to C++. So the C++ style code will be: ...

February 12, 2021 · 2 min · jiezi

关于c++:Acwing算法基础课-二数据结构

数据结构链表与邻链表struct Node{ int val; Node *next}new Node(); //十分慢数组模仿单链表 动态链表int head; //头节点int e[N]; //值int ne[N]; //next指针int idx; //数组用到第几个点// 初始化void init(){ head = -1; idx = 0;}// 在链表头插入一个数avoid insert_head(int a){ e[idx] = a; ne[idx] = head; head = idx; idx++ ;}// 将头结点删除,须要保障头结点存在void remove(){ head = ne[head];}// 将a插入到第k个点前面void add(int k, int a){ e[idx] = a; ne[idx] = ne[k]; ne[k] = idx; idx ++;}//将下标是k的后边的点删掉void remove(int k){ ne[k] = ne[ne[k]];}数组模仿双链表(优化某些问题)每一个点有两个指针 int e[N];int l[N];int r[N];//初始化void init(){ // 0示意左端点(head), 1示意右端点(tail) r[0] = 1; l[1] = 0; idx = 2;}//在下标是k的点的左边,插入xvoid add(int k, int x){ e[idx] = x; r[idx] = r[k]; //不能用 k + 1 l[idx] = k; l[r[k]] = idx; //不能用 k + 1 r[k] = idx; }//在k的右边插入xadd(l[k], x);//删除第k个点void remove(int k){ r[l[k]] = r[k]; l[r[k]] = l[k];}邻接表 存储树和图 ...

February 11, 2021 · 1 min · jiezi

关于c++:CS144-Lab-Assignments-手写TCP-LAB2

CS 144: Introduction to Computer Networking, Fall 2020https://cs144.github.io/My Repohttps://github.com/wine99/cs1... Translating between 64-bit indexes and 32-bit seqnos 留神 wrapping_integers.hh 中的这三个办法: inline int32_t operator-(WrappingInt32 a, WrappingInt32 b) { return a.raw_value() - b.raw_value(); }//! \brief The point `b` steps past `a`.inline WrappingInt32 operator+(WrappingInt32 a, uint32_t b) { return WrappingInt32{a.raw_value() + b}; }//! \brief The point `b` steps before `a`.inline WrappingInt32 operator-(WrappingInt32 a, uint32_t b) { return a + -b; }上面的两个加减,别离是在 WrappingInt32 上加上或减去一个 uint32_t,失去的后果依然是一个 WrappingInt32,其意义是别离为把 a 这个 WrappingInt32 向前或向后挪动 |b| 个单位间隔。 ...

February 10, 2021 · 3 min · jiezi

关于c#:C高级篇初识LINQ

前言揭示:为了可能将知识点学得更加透彻、记得更加牢固 我会通过教学解说的形式把常识写下来 因为在过程中会让人从学生变成老师 这个过程会开掘出新的常识和观点 是一个自我思维切换而达成的常识深度开掘和晋升的过程 如果能帮忙到大家那就最好 如果有讲错的中央还请多多指教!我只是一只菜鸡 感激了解! 1、初识LINQ置信大家多多少少都在网上或者书里看到过LINQ这玩意,那它到底是个什么玩意呢?明天就和大家一起来学习下LINQ LINQ是集成到C#和VB .NET这些语言中用于提供查问数据能力的一个新特色 在关系型数据库中,数据被组织放入规范性很好的表中,并且通过简略而又弱小的语言SQL来进行拜访,然而程序中却与数据库相同,保留在类对象或构造中的数据差别很大,因而没有通用的查问语句来从数据结构中获取数据,自C#3.0引入LINQ后,咱们便有了查问对象数据的能力 就是说LINQ是C#提供给了咱们开发者一个疾速查问数据的能力 LINQ-----------让语言更柔美,让查问更便捷,让代码更杰出。 2、简略的LINQ案例先来一个示例,让大伙看看LINQ的魅力所在 要应用LINQ的话就要援用它所在的命名空间 using System.Linq; using System;using System.Collections.Generic;using System.Linq;namespace ConsoleApp1{ class GameText { public int gameID; //游戏ID public string gameName; //游戏名称 public string gameIntduced; //游戏介绍 public int gameSize; //游戏大小 } class Program { static List<GameText> game = new List<GameText>() { new GameText(){gameID = 1,gameName = "东凑西凑",gameIntduced = "这是一个2D实习面试我的项目",gameSize = 1}, new GameText(){gameID = 2,gameName = "同桌的你",gameIntduced = "这是一个青春校园题材的游戏",gameSize = 5}, }; static void Main(string[] args) { var res = from m in game where m.gameID > 1 select m.gameName; foreach (var item in res) { Console.WriteLine(item); } } }}次要看这个中央 ...

February 10, 2021 · 4 min · jiezi

关于c++:C并发与多线程-8asyncfuturepackagedtaskpromise

std::future类模板template <class T> future;template <class R&> future<R&>; // specialization : T is a reference type (R&)template <> future<void>; // specialization : T is voidfuture 是一个对象,能够从某个提供对象或函数中检索值,如果在不同线程中,则能够正确同步此拜访。“无效” future 对象,通过调用一下函数之一来结构: asyncpromise::get_futurepackaged_task::get_futurefuture 对象仅在他们无效时才有用。默认结构的 future 对象五项(除非挪动调配一个无效的 future)。在无效的 future 上调用 future::get 会阻塞线程,直到提供程序筹备好共享状态(通过设置值或异样)。这样,两个线程能够通过一个线程同步,期待另一个线程设置值。共享状态的生存期至多要继续到与之关联的最初一个对象开释它或销毁它为止。因而,如果与 future 相关联,共享状态能够在最后取得它的对象(如果有的话)之后持续存在。future::valid()bool valid() const noexcept; 查看无效的共享状态返回 future 对象以后是否与共享状态关联。对于默认结构的 future 对象,此函数返回 false (除非将无效的 future 调配给挪动对象)。future 只能由某些提供函数(如, async, promise::get_future 或 packaged_task::get_future)应用无效的共享状态进行初始化。一旦应用 future::get 检索了共享状态的值,则调用此函数返回 false (除非挪动调配了一个新的 future).返回值如果对象与共享状态关联,则为 ture。否则为假。// future::valid#include <iostream> // std::cout#include <future> // std::async, std::future#include <utility> // std::moveint get_value() { return 10; }int main (){ std::future<int> foo,bar; foo = std::async (get_value); bar = std::move(foo); if (foo.valid()) std::cout << "foo's value: " << foo.get() << '\n'; else std::cout << "foo is not valid\n"; if (bar.valid()) std::cout << "bar's value: " << bar.get() << '\n'; else std::cout << "bar is not valid\n"; return 0;}输入: ...

February 9, 2021 · 6 min · jiezi

关于c++:C并发与多线程-8conditionvariablewaitnotifyonenotifyall

std::condition_variable条件变量是一个对象,该对象可能阻塞调用线程,直到被告诉复原。当调用其期待函数(wait,wait_for,wait_until)之一时,它应用 unique_lock (通过互斥锁)来锁定线程,该线程将放弃阻塞状态,直到被另一个同在 condition_variable 对象上调用告诉性能的线程唤醒为止。condition_variable 类型的对象始终应用 unique_lock<mutex> 期待(无关可与任何类型的可锁定类型一起应用的代替办法,可参见 condition_variable_any)。// condition_variable example#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutex, std::unique_lock#include <condition_variable> // std::condition_variablestd::mutex mtx;std::condition_variable cv;bool ready = false;void print_id (int id) { std::unique_lock<std::mutex> lck(mtx); while (!ready) cv.wait(lck); // ... std::cout << "thread " << id << '\n';}void go() { std::unique_lock<std::mutex> lck(mtx); ready = true; cv.notify_all();}int main (){ std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(print_id,i); std::cout << "10 threads ready to race...\n"; go(); // go! for (auto& th : threads) th.join(); return 0;}输入: ...

February 8, 2021 · 2 min · jiezi

关于c++:2021年秋招-双非渣硕的我是如何拿到字节跳动研发岗SP

前言最近应邀在牛客网写C++求职专栏,又把以前的秋招总结补充了很多货色,当初想想还是收回来,心愿可能帮忙更多的老手小伙伴们。 集体状况简介 楼主本硕均读于双非院校(一般二本学校)、本硕都是计算机相关业余,英语六级程度,本科期间辅修了一个水的不能再水的英语第二学位。 本科期间学过很多语言:VB、C、C++、Java、C#都有所涉猎,研究生期间则主攻Python和C++。研二上学期开始零碎学习C++,并且一直零碎看书和实际,两头解体过、迷茫过、放荡过,但从未放弃,始终置信本人,保持咬牙走上来。所幸天道酬勤,最终也是拿到了一些不错的offer 。 投递经验 笔者从2020.6.15号正式开始投递简历,到2020.8.23号截止一共投递过94家公司,其中既有提前批(2020年6月-7月),也包含正式批(2020年7月-10月)。 小倡议:如果说求职者对本身实力不自信,能够多投投一些公司,选择面放宽一些,不要死盯着那几个大厂投。 共计口试59场(最多一天做了5场口试,那天天差点逝世),54家公司给了面试机会,54家企业中有些企业是免口试的。 秋招后果:最终胜利走到了6家公司的offer环节:字节跳动研发岗SP、华为通用软件开发、百度C++研发岗、B站后端研发岗、深服气C++研发岗以及农业银行研发岗,最初签了字节跳动,也是本人心心念念的大厂之一,十分满意了~ 接下来从6个方面对秋招进行复盘和总结,心愿可能帮到大家鸭,特地是大三大四的小学弟们。 1、算法 在秋招过程中,算法是极其重要的,再次重申一遍,真的很重要!口试就不提了,算法不过关,口试根本凉凉,面试根本都要手撕代码,很多面试过程中算法题具备一票否决权,如果你可能顺利解进去,面试也不肯定过。即便面试过了,手撕代码没撕进去,面评估计也是一般般了。然而如果算法题做不进去或者说bug太多调试不通的话,面试上基本上就跪了(集体以及身边敌人经验,不肯定精确),在牛客网上也看到过很多根底很好的牛友就是因为面试过程中的算法题没解进去而间接饮恨的,心愿大家千万器重算法这一块,千万千万要器重算法。 我大略在力扣上刷了300+,HOT100都刷了,剑指offer刷了3遍,刷完这些根本够用了,本人也有留神总结题型,常见题型就是那些,所以算法题根本没怎么拉过我后腿。一般来说,次要考的就是动静布局、贪婪、二叉树、链表、数组、字符串之类的。 举荐材料:力扣1-300题(前300道题十分经典,倡议学有余力的同学都刷一刷) 力扣HOT100(跟下面有不少是反复的,刷的时候要留神总结) 啊哈!算法、大话数据结构(这两本书都是面向老手的图书,图画很多) 剑指offer(这本书不须要多做介绍,校招必备) 挑战程序设计比赛(这本书属于进阶一点的算法书籍了,作者是ACM-ICPC寰球总冠军,能够说是世界顶级程序设计高手的经验总结了,须要缓缓消化,经典题型太多) 程序员代码面试指南(左程云大神的书,我并没有看完,只是看了其中的海量数据处理局部的题目就曾经非常受用了,在某大厂三面中就考查到了其中的海量数据集解决的问题) 2、操作系统 操作系统是比拟重要的,面试三大要点之一(操作系统、计网、数据库),我是在B站上看过一些操作系统视频,同时本人缓缓看书、看博客学的。其中死锁、虚拟内存、堆栈、过程线程、内存治理、磁盘调度等都是重点,也是面试过程中问的比拟多的一些知识点。你如果可能在面试过程中讲进去一些具体的操作系统常识,而不是泛泛而谈,必定是很加分的,比方常见知识点过程线程区别,在提到线程切换比过程更快时,你如果可能很分明明确的说进去过程切换做了哪些、线程切换做了哪些以及线程为什么比过程快,毫无疑问很加分的。 举荐材料:B站哈工大操作系统:https://www.bilibili.com/vide... B站清华大学操作系统:https://www.bilibili.com/vide... B站美国麻省理工MIT 6.828操作系统神级课程:https://www.bilibili.com/vide... 古代操作系统(也是讲操作系统的一本好书,讲的很细) 深刻了解计算机系统(赫赫有名的CSAPP,被誉为“和金子一样重要的计算机根底书籍” , 很厚的一本黑皮书,须要缓缓看) 古代操作系统:原理与实现(上海交通大学陈海波传授的著述,书中次要介绍操作系统的实践与具体实现细节等,感觉不如CSAPP) 3、计算机网络 计算机网络也是重点之一,特地是HTTP以及TCP/UDP相干知识点,算是校招必备考点了,面试必问,然而难度是逐年回升的,起因可能就在于内卷水平越来越重大了吧。比如说以前对于三次握手四次挥手只问过程,当初间接让面试者画出客户端以及服务器端的各个状态码以及解释各种意外状况,比方SYN申请失落会怎么样? 倡议计网的学习先从视频动手,而后再看经典书籍,毕竟视频中的常识都是他人总结好又给你解说的,只有本人亲自琢磨、亲自动手实际得来的常识才是本人的,本人学来的才是真,通过实际方知分晓的~ 举荐材料:B站韩立刚老师的计算机网络(韩老师讲课滑稽易懂,让你在哈哈大笑中学到很多知识点:https://www.bilibili.com/vide...) 图解HTTP、图解TCP/IP(这两本书比较简单,日本人写的,把简单的知识点简单化) 网络是怎么连贯的(这本书紧紧围绕一个问题:输出一个URL,直到咱们在网页端看到申请的内容,这两头产生了什么?抽丝剥茧将这个问题逐渐细化,带你走残缺个网页拜访的过程) 计算机网络:自顶向下办法 (也是常见经典书籍之一,重点看第三章传输层TCP/UDP) 4、Linux C++跟Linux根本是离不开的,特地是后端方向跟网络通信关系很大。在理论工作里,很多成熟的我的项目都是在Linux上进行开发的。所以有必要学一些Linux以及一些网络通信编程,网络通信波及到的知识点很多,比方IO模型、线程池、多线程之类的。自己在秋招过程中被问过不少网络通信的问题,最频繁的就是select、poll、epoll的区别以及相干底层实现了。这里也举荐一些材料,都是我集体看过的。 举荐材料:鸟哥的Linux以及Linux就该这么学这两本书(个人感觉更适宜作为一本工具书来应用,当然了,如果你有短缺的工夫也能够零碎的看上一遍,对于Linux也会有更深的意识和理解了) TCP/IP网络编程(韩国人写的,书中例子很多,适宜作为入门,另外github上有很多笔记,能够边看他人的笔记边看书,加深集体了解) Linux高性能服务器编程(游双老师的书,其中前四五章讲的是计网的货色,前面讲的很好,波及内容很多,看完就大略明确服务端编程常见知识点和所须要把握的技能了) Linux多线程服务端编程:应用muduo C++网络库 (北师大陈硕大神的书,须要很多根本,倡议前期再看,我也只是看了一小半) ...

February 8, 2021 · 1 min · jiezi

关于c:Linux函数学习setsockoptgetsockopt和getsockname函数

简介:setsockopt、getsockopt这两个函数获取套接字一些无关选项和设置套接字无关的套接字。getsockname是通过套接字获取套接字无关的一些信息,例如端口、协定等。 1:int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); sock:将要被设置或者获取选项的套接字。level:选项所在的协定层。optname:须要拜访的选项名。optval:对于getsockopt(),指向返回选项值的缓冲。对于setsockopt(),指向蕴含新选项值的缓冲。optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为进口参数时,选项值的理论长度。对于setsockopt(),现选项的长度。对于level和optname具体参数如下level指定管制套接字的档次.能够取三种值:1)SOL_SOCKET:通用套接字选项.2)IPPROTO_IP:IP选项.3)IPPROTO_TCP:TCP选项. 返回阐明: 胜利执行时,返回0。失败返回-1,errno被设为以下的某个值 EBADF:sock不是无效的文件形容词EFAULT:optval指向的内存并非无效的过程空间EINVAL:在调用setsockopt()时,optlen有效ENOPROTOOPT:指定的协定层不能辨认选项ENOTSOCK:sock形容的不是套接字optval取得或者是设置套接字选项.依据选项名称的数据类型进行转换 选项名称 阐明 数据类型======================================================================== SOL_SOCKET------------------------------------------------------------------------SO_BROADCAST 容许发送播送数据 intSO_DEBUG 容许调试 intSO_DONTROUTE 不查找路由 intSO_ERROR 取得套接字谬误 intSO_KEEPALIVE 放弃连贯 intSO_LINGER 提早敞开连贯 struct lingerSO_OOBINLINE 带外数据放入失常数据流 intSO_RCVBUF 接收缓冲区大小 intSO_SNDBUF 发送缓冲区大小 intSO_RCVLOWAT 接收缓冲区上限 intSO_SNDLOWAT 发送缓冲区上限 intSO_RCVTIMEO 接管超时 struct timevalSO_SNDTIMEO 发送超时 struct timevalSO_REUSERADDR 容许重用本地地址和端口 intSO_TYPE 取得套接字类型 intSO_BSDCOMPAT 与BSD零碎兼容 int======================================================================== IPPROTO_IP------------------------------------------------------------------------IP_HDRINCL 在数据包中蕴含IP首部 intIP_OPTINOS IP首部选项 intIP_TOS 服务类型IP_TTL 生存工夫 int======================================================================== IPPRO_TCP------------------------------------------------------------------------TCP_MAXSEG TCP最大数据段的大小 intTCP_NODELAY 不应用Nagle算法 int========================================================================int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len); 性能:获取一个套接字的选项 参数: socket:文件描述符 level:协定档次 SOL_SOCKET 套接字档次 IPPROTO_IP ip档次 IPPROTO_TCP TCP档次 option_name:选项的名称(套接字档次) SO_BROADCAST 是否容许发送播送信息 SO_REUSEADDR 是否容许重复使用本地地址 SO_SNDBUF 获取发送缓冲区长度 SO_RCVBUF 获取接收缓冲区长度 SO_RCVTIMEO 获取接管超时工夫 SO_SNDTIMEO 获取发送超时工夫 option_value:获取到的选项的值 option_len:value的长度 返回值: 胜利:0 失败:-1int getsockname(int sockfd, struct sockaddr *localaddr,socklen_t *addrlen); getsockname能够取得一个与socket相干的地址。 服务器端能够通过它失去相干客户端地址。 而客户端也能够失去以后已连贯胜利的socket的ip和端口。 对于TCP连贯的状况,如果不进行bind指定IP和端口,那么调用connect连贯胜利后, 应用getsockname能够正确取得以后正在通信的socket的IP和端口地址。 而对于UDP的状况,无论是在调用sendto之后还是收到服务器返回的信息之后调用, 都无奈失去正确的ip地址:应用getsockname失去ip为0,端口正确。 2:在Tinyhttpd中有相似的例子,如下代码 ...

February 8, 2021 · 1 min · jiezi

关于c++:C并发与多线程-7单例设计模式callonce

懒汉式单例类#include <iostream>#include <thread>#include <mutex>using namespace std;class Singleton{public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; static Singleton* instance; static mutex mtx;};Singleton *Singleton::instance = nullptr;mutex Singleton::mtx;Singleton* Singleton::getInstance(){ if (instance == nullptr) { lock_guard<mutex> lck(mtx); // 留神这里 !!! if (instance == nullptr) { instance = new Singleton(); } } return instance;}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}饿汉式单例类#include <iostream>#include <thread>using namespace std;class Singleton{public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; static Singleton* instance;};Singleton *Singleton::instance = new Singleton(); // 留神这里 !!!Singleton* Singleton::getInstance(){ return instance;}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}懒汉式的 call_once 实现template <class Fn, class... Args> void call_once (once_flag& flag, Fn&& fn, Args&&... args);精确执行一次可调用对象 fn ,即便同时从多个线程调用。#include <iostream>#include <thread>#include <mutex>using namespace std;class Singleton{public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; static void createInstance(); static Singleton* instance; static once_flag onceFlag;};void Singleton::createInstance(){ instance = new Singleton();}Singleton *Singleton::instance = nullptr;once_flag Singleton::onceFlag;Singleton* Singleton::getInstance(){ call_once(onceFlag, createInstance); // 留神这里 !!! return instance;}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}单例类的资源清理【饿、懒同理】#include <iostream>#include <thread>#include <mutex>using namespace std;class Singleton{ struct Recycle { ~Recycle() // 留神这里 !!! { if (instance != nullptr) { delete instance; instance = nullptr; } } };public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; ~Singleton(); static Singleton* instance; static mutex mtx;};Singleton *Singleton::instance = nullptr;mutex Singleton::mtx;Singleton* Singleton::getInstance(){ if (instance == nullptr) { lock_guard<mutex> lck(mtx); if (instance == nullptr) { instance = new Singleton(); static Recycle recycle; } } return instance;}Singleton::~Singleton() // 留神这里 !!!{ // 单例类资源清理}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}

February 7, 2021 · 2 min · jiezi

关于c++:C并发与多线程-6uniquelock-类模板详解

unique_lock 取代 lock_guardstd::lock_guard 和 std::unique_lock 都能实现主动加锁与解锁性能。std::unique_lock 外部持有 mutex 的状态(locked,unlocked),因而比 lock_guard 应用更加灵便但同时更占用空间、速度更慢。// unique_lock example#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutex, std::unique_lockstd::mutex mtx; // mutex for critical sectionvoid print_block (int n, char c) { // critical section (exclusive access to std::cout signaled by lifetime of lck): std::unique_lock<std::mutex> lck (mtx); for (int i=0; i<n; ++i) { std::cout << c; } std::cout << '\n';}int main (){ std::thread th1 (print_block,50,'*'); std::thread th2 (print_block,50,'$'); th1.join(); th2.join(); return 0;}输入: ...

February 7, 2021 · 4 min · jiezi

关于c:树的解读

前沿前几期文章我介绍了链表,队列,栈这些都是线性构造的存储形式。明天咱们来看看非线性构造的树 定义业余的定义: 有且只有一个称为根的节点有若干个互不相交的子树,这些子树自身也是一颗树艰深的定义: 树是由节点和边组成每个节点只有一个父节点但能够有多个子节点但有一个节点例外,该节点没有父节点,此节点称为根节点专业术语: 深度:从根节点到最底层节点的层数称之为深度(根节点是第一层)叶子节点:没有子节点的节点非终端节点:理论就是非叶子节点(根节点既能够是叶子也能够是非叶子节点)度:子节点的个数称为度(一棵树看最大的)分类树的分类 个别树任意一个节点的子节点的个数都不受限制,子节点的程序能够更改也能够不能更改,能更改的树为无序个别树,不能更改的为有序个别树 二叉树 任意一个节点的子节点个数最多两个,且子节点的地位不可更改,即左子树和右子树的地位不可更改。 分类: 个别二叉树满二叉树:在不减少树的层数的前提下,无奈再多增加一个节点的二叉树就是满二叉树 齐全二叉树:如果只是删除了满二叉树最底层最左边的间断若干个节点,这样造成的二叉树就是齐全二叉树。 存储: 间断存储:间断存储用数组存储【实用于齐全二叉树,不是齐全二叉树的树补充为齐全二叉树】 长处 : 查找某个节点的父节点和子节点(也包含判断有没有子节点)方便快捷 毛病: 耗费内存空间过大 链式存储:链式存储两个指针域别离指向两个子节点,没有子节点的为空 长处:耗用内存空间小 毛病:查找父节点不不便 算法咱们来看看经典的二叉树的前中后序遍历 一、首先来看看先序遍历先拜访根节点再先序拜访左子树再先序拜访右子树//先序遍历伪代码void PreTraverseBTree(PBTNODE pT){ if (pT != NULL) { printf("%c\n", pT->data); PreTraverseBTree(pT->pLchild); PreTraverseBTree(pT->pRchild); }}先序遍历后果 A B C D E 二、再来看看中序遍历中序遍历左子树再拜访根节点再中序遍历右子树//中序遍历伪代码void MidTraverseBTree(PBTNODE pT){ if (pT != NULL) { MidTraverseBTree(pT->pLchild); printf("%c\n", pT->data); MidTraverseBTree(pT->pRchild); }}中序遍历后果 B A D E C 三、最初是后序遍历先后序遍历左子树再后序遍历右子树再拜访根节点//后序遍历伪代码void LastTraverseBTree(PBTNODE pT){ if (pT != NULL) { LastTraverseBTree(pT->pLchild); LastTraverseBTree(pT->pRchild); printf("%c\n", pT->data); }}后序遍历后果 B E D C A ...

February 6, 2021 · 1 min · jiezi

关于c:Linux函数学习getoptgetoptlonggetoptlongonly

简介:这几个函数是对相似于main函数那样传进来的参数进行解析。参数的指定由-key value -key --key value --key -key value1 value2 这几种类型,其中getopt能够解决前两种类型,getopt_long可能解决所有类型的参数解析,getopt_long_only相似于getopt_long,能够解决所有选项。具体细节再前面的局部进行介绍。 首先介绍getopt选项,他是绝对比较简单的。函数原型: int getopt(int argc, char * const argv[], const char *optstring);argc和argv就是main函数传进来的参数,在这里就不多说了。optstring:此参数是指定咱们要解析的参数内容。eg:abc:(注,getopt函数只能解决带一个冒号的optstring)optind:是下一次调用getopt函数该当解决参数的小标,也就是argv要解决参数的下表。optarg:是带有一个冒号的optstringopterr:此选项决定是否将谬误音讯打印到规范谬误中,如果是0的话,就不打印谬误了。上面是一个例子和对应的输入。 接下来解说getopt_long函数,后面说过,此函数可能解决所有的参数函数原型: int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);此函数多了两个参数第一个参数构造如下。struct option { const char *name; int has_arg; int *flag; int val; };name:此局部代表长选项的名称。has_arg:此构造有几个宏为其赋值。 no_argument(0):代表没有对应的值 required_argument(1) :代表肯定须要一个值。 optional_argument(2):代表有没有对应的值都能够。 flag:如果此选项不为空的话,那么将参数对应的val赋值给flag,否则返回。 val:就是咱们要返回后者付给flag对应的value。longindex:如果此选项不为空的话,那么它将指向绝对于longopts对应的下标。上面是我给出的一个例子:和一些输入。 getopt_long_only与上述getopt_long不同之处:前者不论是“-”还是“--”都视为长选项,如果找不到的话,才去短选项哪里查找:

February 6, 2021 · 1 min · jiezi

关于c#:Win32Api-关闭当前应用

本文介绍Windows零碎下应用Win32API获取以后利用并敞开的办法。 思路应用EnumWindows接口枚举以后窗口;过滤掉不可用、暗藏、最小化的窗口;过滤掉子窗口;通过题目、类名过滤掉零碎窗口;应用PostMessage发送敞开窗口信息。具体实现// 过滤掉零碎的一些窗口private static string[] filterTitles = new string[1] { "program manager"};private static string[] filterClasses = new string[5] { "shell_traywnd", "workerw", "button", "progman", "windows.ui.core.corewindow"};private void CloseCurrentApp(){ CallBack sort = new CallBack(EnumCallback); EnumWindows(sort, 0); return;}private bool EnumCallback(IntPtr hwnd, int lParam){ string title = GetWindowText(hwnd); StringBuilder className = new StringBuilder(256); int nRet = GetClassName(hwnd, className, className.Capacity); if (nRet == 0) className.Append(""); if (!IsWindowVisible(hwnd)) return true; if (!IsWindowEnabled(hwnd)) return true; if (IsIconic(hwnd)) return true; // 过滤掉子窗口 IntPtr parent = GetParent(hwnd); string parentTitle = GetWindowText(parent); if (parent != IntPtr.Zero) { if (IsWindowVisible(parent) && IsWindowEnabled(parent)) return true; } IntPtr owner = GetWindow(hwnd, GW_OWNER); if (owner != IntPtr.Zero) { if (IsWindowVisible(owner) && IsWindowEnabled(owner)) return true; } if (!filterTitles.Contains(title.ToLower()) && !filterClasses.Contains(className.ToString().ToLower())) { PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); Console.WriteLine("敞开窗口(句柄:{0}, 题目:{1})!", hwnd, title); #region 获取窗口信息 int processID = -1; long threadID = -1; processID = GetWindowThreadProcessId(hwnd, out threadID); bool isiconic = IsIconic(hwnd); uint gwlStyle = (uint)GetWindowLong(hwnd, GWL_STYLE); IntPtr hProcess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processID); string fullPath = ""; if (hProcess != IntPtr.Zero) { int capacity = 1024; StringBuilder processName = new StringBuilder(capacity); QueryFullProcessImageName(hProcess, 0, processName, ref capacity); fullPath = processName.ToString(0, capacity); CloseHandle(hProcess); } Console.WriteLine("-------------------窗口info:---------------"); Console.WriteLine("====题目:{0} 句柄:{1}====", title, hwnd); Console.WriteLine("====父窗口题目:{0} 父窗口句柄:{1}====", parentTitle, parent); Console.WriteLine("====过程ID:{0} 类名:{1}====", processID, className.ToString()); Console.WriteLine("====过程名:{0}====", fullPath); Console.WriteLine("====isiconic:{0} 款式:{1}====", isiconic, gwlStyle); WINDOWPLACEMENT placement = new WINDOWPLACEMENT(); placement.length = System.Runtime.InteropServices.Marshal.SizeOf(placement); GetWindowPlacement(hwnd, ref placement); Console.WriteLine("====placement:{0}====", placement.showCmd); EnumPropsDelegate prop = new EnumPropsDelegate(EnumPropsProc); EnumProps(hwnd, prop); #endregion 获取窗口信息 return false; } return true;}private bool EnumPropsProc(IntPtr hwnd, IntPtr lpszString, IntPtr hData){ string propName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(lpszString); Console.WriteLine("====属性:{0} 数据:{1}====", propName, hData); return true;}#region Win32Apipublic const int GWL_STYLE = (-16);public const int GWL_EXSTYLE = (-20);public const int GW_OWNER = 4;public const int WS_EX_TOOLWINDOW = 0x00000080;public const int WM_SYSCOMMAND = 0x0112;public const int WM_CLOSE = 0x10;public const int SC_CLOSE = 0xF060;public delegate bool CallBack(IntPtr hwnd, int lparam);public delegate bool EnumPropsDelegate(IntPtr hwnd, IntPtr lpszString, IntPtr hData);[DllImport("user32.dll")]public static extern int EnumWindows(CallBack x, int y);[DllImport("user32.dll", CharSet = CharSet.Auto)]internal static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);[DllImport("user32.dll", CharSet = CharSet.Auto)]public static extern int GetWindowTextLength(IntPtr hWnd);[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);[DllImport("user32.dll")]public static extern bool IsWindowVisible(IntPtr hwnd);[DllImport("user32.dll")]public static extern bool IsWindowEnabled(IntPtr hwnd);[DllImport("user32.dll", EntryPoint = "IsIconic")]public static extern bool IsIconic(IntPtr hWnd);[DllImport("user32.dll", SetLastError = true)]public static extern IntPtr GetParent(IntPtr hwnd);[DllImport("user32.dll", SetLastError = true)]public static extern IntPtr GetWindow(IntPtr hwndParent, int nCmd);[DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]public static extern long GetWindowLong(IntPtr hwnd, int nIndex);[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]public static extern bool PostMessage(IntPtr hwnd, uint Msg, uint wParam, uint lParam);[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern int GetWindowThreadProcessId(IntPtr hWnd, out long lpdwProcessId);[DllImport("kernel32.dll", SetLastError = true)]public static extern IntPtr OpenProcess( ProcessAccessFlags processAccess, bool bInheritHandle, int processId);[DllImport("kernel32.dll", SetLastError = true)]public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]System.Text.StringBuilder lpExeName, ref int lpdwSize);[DllImport("coredll.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto)][return: MarshalAs(UnmanagedType.Bool)]public static extern bool CloseHandle(IntPtr hObject);[DllImport("user32.dll", SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);[DllImport("user32.dll")]public static extern int EnumProps(IntPtr hWnd, EnumPropsDelegate lpEnumFunc);public struct WINDOWPLACEMENT{ public int length; public int flags; public int showCmd; public System.Drawing.Point ptMinPosition; public System.Drawing.Point ptMaxPosition; public System.Drawing.Rectangle rcNormalPosition;}[Flags]public enum ProcessAccessFlags : uint{ All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VirtualMemoryOperation = 0x00000008, VirtualMemoryRead = 0x00000010, VirtualMemoryWrite = 0x00000020, DuplicateHandle = 0x00000040, CreateProcess = 0x000000080, SetQuota = 0x00000100, SetInformation = 0x00000200, QueryInformation = 0x00000400, QueryLimitedInformation = 0x00001000, Synchronize = 0x00100000}public static string GetWindowText(IntPtr hwnd){ int capacity = GetWindowTextLength(hwnd) * 2; System.Text.StringBuilder lpString = new System.Text.StringBuilder(capacity); GetWindowText(hwnd, lpString, lpString.Capacity); if (lpString.Length > 0) { return lpString.ToString(); } return string.Empty;}#endregion Win32Api

February 6, 2021 · 3 min · jiezi

关于c++:QFtp源码学习及目录下载

背景须要在QT5中进行FTP文件下载,并须要反对整目录下载,通过比照抉择,最初决定应用Qt4中的QFtp来实现咱们的需要。因而决定学习源码,看清构造,做到能真正解决所要面对的问题。 合成源码Qftp一共只有四个文件,次要文件是qftp.cpp,这个文件中,有太多的类,首先按类合成到各自文件中,这样利用官网的示例代码,跑起来后,能够不便的查看代码。 类阐明class QFtpCommand : 此类是对FTP命令的封装,将命令与QIODevice设施关联起来,并返回一个惟一的标识ID。class QFtpPI : 此类是对FTP协定的封装,processReply是次要函数,应答服务端响应。class QFtpDTP : 此类是数据操作封装,数据读取、解析、存储都是在此类中解决。class QFtpPrivate : 此类是QFtp的实际操作类,被组合到QFtp类中,是逻辑解决核心。class QFtp : 此类是外壳,用户间接面对。class QUrlInfo : 此为信息类,存储接管到的每一条文件数据信息。运行流程所有的客户端命令被压入到命令堆栈。一个命令运行有两个入口:一是命令被压入堆栈时,若堆栈中只有一条命令,即被运行;二是作响应服务端响应时,类型为idle或not waiting。每个命运被结构时,都会返回惟一ID,这是很重要的一点,因为命令大多关联着一本地IO设施,在清理IO时,要留神与命令对应,因为所有的操作都是异步的。 革新list响应QFtp列当前目录的原有逻辑是取一条数据就发送一条文件或目录的音讯,这样在咱们间断遍历目录时,无奈分分明是哪个目录下的数据,无奈进行正确的递归。QFtpDTP::socketReadyRead() - 批改读取目录列表时的信号发送形式 if (pi->currentCommand().startsWith(QLatin1String("LIST"))) { QVector<QUrlInfo> infos; //减少vector来存储整个目录信息 while (socket->canReadLine()) { QUrlInfo i; QByteArray line = socket->readLine(); if (parseDir(line, QLatin1String(""), &i)) { infos.push_back(i); //emit listInfo(i); //原来在循环内,读一条数据发送一个listInfo信号 } else { if (line.endsWith("No such file or directory\r\n")) err = QString::fromLatin1(line); } } emit listInfos(infos); //改为在循环外发送新增的listInfos信号 }FtpWindow::addToList(const QVector<QUrlInfo>& urlInfos) - listInfos响应批改 ...

February 6, 2021 · 2 min · jiezi

关于c:Linux学习tcpdump表达式及命令参数详解例子

1:tcpdump抓取各种类型的包。tcp规定只有一套,然而它有两种用处。一个是用于显示抓取到的包、另一个是用于抓包。当然有些options只能用于抓取包,有些options只能用于显示包。同时、tcpdump命令提供表达式,此项性能能够过滤掉咱们抓到大包,只去显示或存储咱们想要的包。废话不多说,上面开始介绍tcp。(这其中我也有许多参数弄不明确、心愿懂的人可能再评论区下方加以评论)。 首先、是总体看tcp这个命令都有哪些opitons 。 tcpdump [ -AbdDefhHIJKlLnNOpqStuUvxX# ] [ -B buffer_size ] [ -c count ] [ -C file_size ] [ -G rotate_seconds ] [ -F file ] [ -i interface ] [ -j tstamp_type ] [ -m module ] [ -M secret ] [ --number ] [ -Q in|out|inout ] [ -r file ] [ -V file ] [ -s snaplen ] [ -T type ] [ -w file ] [ -W filecount ] [ -E spi@ipaddr algo:secret,... ] [ -y datalinktype ] [ -z postrotate-command ] [ -Z user ] [ --time-stamp-precision=tstamp_precision ] [ --immediate-mode ] [ --version ] [ expression ]从上述能够看的进去、tcp有许多选项,我会将我不懂的中央标记进去、心愿各位大神可能加以探讨。我这里可能不是依照上述书写的程序定义。-i:指定咱们要抓取的接口。-D:列出咱们能够应用该命令抓取包的网络接口。如下图所示 ...

February 6, 2021 · 1 min · jiezi

关于c#:一种圆形识别方案

本文介绍一种圆形的辨认计划。 辨认流程判断是否为关闭图形;依据圆的方程,取输出点集中的1/6、3/6、5/6处的三个点,求得圆的方程,获取圆心及半径;取点集中的局部点,计算点到圆心的间隔与半径的比例,与设定的阈值比拟,得出后果。~~~~实现public static bool IsCircle(List<Point> points, out Point center, out double radius){ int len = points.Count; center = new Point(); radius = 0; // 判断是否为关闭图形 if (!IsClosedFigure(points)) return false; int judgePointNum = len * 50 / 100; if (len < judgePointNum) return false; // 取链表上三个点作为判断圆的依据 Point p1 = points[len / 6]; Point p2 = points[len / 2]; Point p3 = points[len * 5 / 6]; if ((Math.Abs(p1.X - p2.X) < 100 && Math.Abs(p1.Y - p2.Y) < 100) || (Math.Abs(p1.X - p3.X) < 100 && Math.Abs(p1.Y - p3.Y) < 100) || (Math.Abs(p2.X - p3.X) < 100 && Math.Abs(p2.Y - p3.Y) < 100)) return false; // 三个点确定圆的方程,获取圆心坐标及半径 GetCircle(p1, p2, p3, out center, out radius); // 获取圆上均匀分部的多个点,判断其到圆心的间隔与半径之差是否在精度内 for (int i = 0; i < judgePointNum; ++i) { // 获取圆上点 Point p = points[len * i / judgePointNum]; double deviation = Math.Abs(GetDistance(center, p) - radius); // 点在圆上的偏移量与半径的比值若大于固定值,则不为圆 if (deviation/radius > MaxRatio) return false; } return true;}

February 6, 2021 · 1 min · jiezi

关于c#:进击吧Blazor第一章-4数据交互

《进击吧!Blazor!》是自己与张善友老师单干的Blazor零根底入门系列视频,此系列能让一个从未接触过Blazor的程序员把握开发Blazor利用的能力。视频地址:https://space.bilibili.com/48...演示代码:https://github.com/TimChen44/...本系列文章是基于《进击吧!Blazor!》直播内容编写,降级.Net5,改良问题,解说更全面。作者:陈超超Ant Design Blazor 我的项目贡献者,领有十多年从业教训,长期基于.Net技术栈进行架构与开发产品的工作,现就职于正泰团体。邮箱:timchen@live.com欢送各位读者有任何问题分割我,咱们共同进步。 上一次课程咱们实现了ToDo利用的界面制作,这次咱们要将客户端的数据写入数据库,并从数据库中读物咱们须要的数据。 数据交互过程咱们先看一下从客户端到数据库的流程 BlazorBlazor客户端就是咱们上节课做的ToDo程序。 HttpClientHttpClient就是咱们实现网络通讯用的组件,对于这类组件咱们心愿在一个利用中只结构一次,这样防止反复分配资源,因而咱们在Program.cs中进行注册。 public class Program{ public static async Task Main(string[] args) { builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); }}BaseAddress为基地址,这样咱们应用时,Url只须要传入绝对地址即可,此处默认为以后主机的地址。DefaultRequestHeaders 默认HTTP申请头参数Timeout 连贯超时参数 依赖关系注入下面通过服务注入的形式实现了HttpClient全局共享(单例),那么如何应用服务?这里咱们就须要引入一下“依赖关系注入 (DI)”的概念。 DI是一种技术,基本原理是把有依赖关系的类放到容器中,解析出这些类的实例,就是依赖注入。利用可通过将内置服务注入组件来应用这些服务。 利用还可定义和注册自定义服务,并通过 DI 使其在整个利用中可用。 该技术在 Blazor 利用中常用于以下两个方面: 服务生存期决定了服务何时创立,何时销毁,有三种模式: Scoped:Blazor WebAssembly 利用以后没有 DI 范畴的概念。 已注册 Scoped 的服务的行为与 Singleton 服务相似。 然而,Blazor Server 托管模型反对 Scoped 生存期。 在 Blazor Server 利用中,Scoped服务注册的范畴为“连贯”。 因而,即便以后用意是在浏览器中运行客户端,对于范畴应限定为以后用户的服务来说,首选应用 Scoped 服务。 Singleton:DI 创立服务的单个实例。 须要 Singleton 服务的所有组件都会接管同一服务的实例。 ...

February 5, 2021 · 6 min · jiezi

关于c++:2021寒假刷题-洛谷P1135-BFS初学

总结: queue队列的应用memeset函数的应用BFS: 广度优先搜寻(breadth-fifirst searching,bfs),尽量广阔地搜寻,在每一步优先拜访间隔最近的结点。因为BFS须要依照 接触到的程序 来拜访,所以须要一种先入先出的数据结构——队列来辅助实现。当咱们搜寻一个结点时,将它所有的分支推入队列;解决完以后结点后,再从队列头取出下一个结点持续进行搜寻。#include<bits/stdc++.h>using namespace std;/*思路: 5 1 5 楼层:1 2 3 4 5 按钮:3 3 1 2 5 将楼层A压入队列中,而后找非法的上下楼 压入队列 一直出队 入队 直到B出队就找到了 */const int MAXN = 205;int flr[MAXN]; //存储按钮 int dis[MAXN];//寄存按按钮次数int main(){ int n,a,b; cin>>n>>a>>b; for(int i = 1;i<=n;i++){ cin>>flr[i]; } memset(dis,-1,sizeof(dis)); //memset函数初始化只能是: 0,-1 ,0x3f dis[a]= 0; queue<int> q;//创立队列, int类型 q.push(a); //把a压入队列 while(!q.empty()){ //判断是否非空 int x = q.front(); //取第一个值,front 只是返回这个值,并没有把这个值入列 q.pop(); //出列 if(x == b){ cout<<dis[x]<<endl; return 0; //这里没有写break;输出后果之后间接完结了,间接return 0即可 } int y; //下一步达到的楼层 y = x-flr[x]; if(y>0 && dis[y]==-1){ //要判断这个楼层之前没有拜访过,不然会反复拜访 dis[y] = dis[x]+1; //达到y层须要的按键次数 q.push(y); //达到了之后要把y入队 持续下一轮的判断 } y = x+flr[x]; if(y<=n && dis[y]==-1){ dis[y] = dis[x]+1; q.push(y); } } cout<<-1<<endl;}

February 5, 2021 · 1 min · jiezi

关于c++:More-Effective-C总结笔记二异常

异样条款9:利用destructors防止泄露资源只有保持这个规定,把资源封装在对象内(相似智能指针shared_ptr),通常便能够在exceptions呈现时防止泄露资源。简略来说就是,当有资源可能在函数抛异样时而无奈开释,这时能够将资源封装到对象内(RAII),利用对象的析构函数来主动开释资源,这样即便有exceptions产生,也不会有资源泄露。条款10:在constructors内阻止资源泄露(resource leak)C++只会析构已结构实现的对象。对象只有在其constructor执行结束才算是实现结构得当。因为C++不主动清理那些“结构期间抛出exceptions”的对象,所以你必须设计你的constructors,使它们在那种状况下亦能自我清理。通常这只须要将所有可能的exceptions捕获起来,执行某种清理工作,而后从新抛出exception,使它持续流传进来即可。然而,更优雅的做法实际上是将这些须要在constructor内初始化的对象视为资源,将它们交由智能指针来治理。论断是:如果你以auto_ptr(C++11后应用shared_ptr或者unique_ptr)对象来取代pointer class members,你便对你的constructors做了强化工事,罢黜了“exceptions呈现时产生资源泄露”的危机,不再须要在destructors内亲自动手开释资源,并容许const member pointers得以和non-const member pointers有着一样优雅的解决形式。条款11:禁止异样(exceptions)流出destructors之外Session::Session(){ try { logDestruction(this); } catch (...) { }}这里的catch语句块看起来什么都没做,然而表面容易骗人。这个语句块阻止了“logDestruction所抛出的exceptions”传出Session destructor之外。有两个好理由反对咱们“全力阻止exceptions传出destructors之外”。第一,它能够防止terminate函数在exception流传过程的栈开展(stack-unwinding)机制中被调用;第二,它能够帮助确保destructors实现其应该实现的所有事件。条款12:理解“抛出一个exception”与“传递一个参数”或“调用一个虚函数”之间的差别“抛出exception”与“传递参数”的相同点是:它们的传递形式有3中:by value(传值),by reference(传援用),by pointer(传指针)。然而视你所传递的是参数或exceptions,产生的事件可能齐全不同。起因是当你调用一个函数,控制权最终会回到调用端(除非函数失败以至于无奈返回),然而当你抛出一个exception,控制权不会再回到抛出端。“抛出exception”与“传递参数”的区别一:C++特地申明,一个对象被抛出作为exception时,总是会产生复制(copy)。即便catch语句参数时by reference,或者抛出对象申明为static也一样会产生复制。且复制动作永远是以对象的动态类型为本。“exception objects必定会造成复制行为”这一事实也解释了“传递参数”和“抛出exception”之间的另一个不同:后者经常比前者慢。一般而言,你必须应用一下语句:throw;能力从新抛出以后的exception,其间没有机会让你扭转被流传的exception的类型。此外,它也比拟有效率,因为不须要产生新的exception object。 “抛出exception”与“传递参数”的区别二:函数调用过程中将一个长期对象传递给一个non-const reference参数时不容许的,但对exception则属非法。“抛出exception”与“传递参数”的区别三:一般而言,调用函数传递参数过程中容许的隐式转换在“exceptions与catch子句相匹配”的过程中使不会产生的。“exceptions与catch子句相匹配”的过程中,仅有两种转换能够产生。第一种是“继承架构中的类转换”。第二种是从一个“有型指针”转为“无型指针”(所以一个参数为const void*的catch子句,可捕获任何指针类型的exception)。“抛出exception”与“传递参数”的区别四:catch子句总是依呈现程序做匹配尝试。与虚函数调用比拟,虚函数采纳”best fit“(最佳吻合)策略,而exception解决机制采纳”first fit“(最先吻合)策略。因而,相对不要将”针对base class而设计的catch子句“放在”针对derived class而设计的catch子句“之前。条款13:以by reference形式捕获exceptions相比于by reference形式,以by value形式捕捉exception,会使被传递的对象产生两次复制,产生两个正本。其中一个结构动作用于“任何exceptions都会产生的长期对象”身上,另一个结构动作用于“将长期对象复制到catch的参数上”。千万不要抛出一个指向部分对象的指针,因为该部分对象会在exception传离其scope时被销毁,因而catch子句会取得一个指向“已被销毁的对象”的指针。如果catch by reference,你就能够避开对象删除问题(by pointer会面对的)——它会让你动辄得咎,做也不是,不做也不是;你也能够避开exception objects的切割问题(派生类对象的exception objects被捕获并被视为基类对象的exception objects,将失去其派生成分。对象切割问题是因为动态编联导致的,应用援用和指针时不会产生);你能够保留捕获C++规范exceptions的能力;你也束缚了exception objects需被复制的次数。条款14:理智使用exception specificationsexception specification示例,一个只抛出int类型exceptions的函数申明为:void fun() throw(int);如果函数抛出一个并未列入exception specification的exception,这个谬误会在运行期间被测验进去,于是非凡函数unexpected会被主动调用。unexpected的默认行为是调用terminate。想要防止这种unexpected的办法就是: 不应该将templates和exception specifications混合应用。如果A函数内调用了B函数,而B函数无exception specifications,那么A函数自身也不要设定exception specifications。解决“零碎”可能抛出的exceptions(如bad_alloc)。C++容许你以不同类型的exceptions取代非预期的exceptions。如果非预期函数的替代者从新抛出以后的exception,该exception会被规范类型bad_exception取而代之。void convertUnexpected(){ throw;}set_unexpected(convertUnexpected);如果你做了上述安顿,并且每一个exception specifications都含有bad_exception,或者其基类,你就再也不用放心程序会于是非预期的exception时中止执行。理解异样解决(exception handling)的老本为了让exception的相干老本最小化,只有可能不反对exceptions,编译器便不反对;请将你对try语句块和exception specifications的应用限度于非用不可的地点,并且在真正异样的状况下才抛出exceptions。

February 5, 2021 · 1 min · jiezi

关于c#:Selenium爬虫实战截取网页上的图片

前言同样是为了刷课,没想到工作后仍然和大学一样逃脱不了须要刷网课的命运…… 注释间接说干货了,截取图片,须要截取的图片是什么图片大家都懂(说的就是你,验证码),其余图片的话不须要截取,间接拿到地址下载就行,验证码不行,同样的地址再拜访一次内容就变了。 我不晓得为啥selenium不能间接把特定img元素的图片拿进去,太反人类了。 依据我找到的材料,次要有两种思路,一种是模仿鼠标操作,在验证码下面点击右键,而后抉择另存为,把验证码保留到本地之后再来读取…… 我不了解为啥有这种这么思路清奇的操作,右键另存为的一个很大问题就是你基本没法管制图片存在那里,这也导致这个爬虫程序不具备通用性!所以间接pass掉。 另一种是先对整个网页截图,而后再依照验证码img元素的地位和大小,定位并且裁剪出小的验证码图片来,现实状况下是能够的,然而通过我屡次测试发现不同浏览器裁剪进去图片有不同偏移和缩放,不晓得是哪里出了问题,只能硬编码微调,吐了。只管办法不完满,然而也勉强够用吧,分享一下代码…… 代码这次是用C#(WinForm)做的,尽管只是代码片段,不过截图+裁剪保留局部还是能够参考一下的。 前面的验证码辨认是顺带加上的,用了百度的接口,准确率堪忧。 setStatusMsg1("正在提取验证码");var verifyCode = currentBrowser.WebDriver.FindElement(By.XPath("/html/body/spk-root/spk-login-page/div/section/div[3]/div[2]/div[2]/form/div[3]/div[2]/img"));setStatusMsg2("浏览器截屏");// 设置浏览器大小currentBrowser.WebDriver.Manage().Window.Size = new Size(1280, 800);// 浏览器截屏var screenshot = ((ITakesScreenshot)currentBrowser.WebDriver).GetScreenshot();var screenImagePath = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid().ToString("N")}.jpg");// 保留截屏图片setStatusMsg2("保留截屏");screenshot.SaveAsFile(screenImagePath, ScreenshotImageFormat.Jpeg);// 裁剪验证码setStatusMsg2("裁剪验证码");var codeImagePath = screenImagePath.Replace(".jpg", "_code.jpg");int x, y, width, height;// 应用js来获取图片的地位等信息switch (currentBrowser.BrowserType) { case BrowserEnum.Chrome: x = Convert.ToInt32((long)((IJavaScriptExecutor)currentBrowser.WebDriver).ExecuteScript("return document.querySelector('body > spk-root > spk-login-page > div > section > div.login-body.clearfix > div.login-right > div.form-con > form > div.qr-code > div.qrcode-box.clearfix > img').x")); y = Convert.ToInt32((long)((IJavaScriptExecutor)currentBrowser.WebDriver).ExecuteScript("return document.querySelector('body > spk-root > spk-login-page > div > section > div.login-body.clearfix > div.login-right > div.form-con > form > div.qr-code > div.qrcode-box.clearfix > img').y")); width = verifyCode.Size.Width; height = verifyCode.Size.Height; // 验证码地位调整 //x += 20; //y += 8; // 验证码大小调整 width += 30; height += 15; break; default: x = verifyCode.Location.X; y = verifyCode.Location.Y; width = verifyCode.Size.Width; height = verifyCode.Size.Height; break;}var codeBitmap = new Bitmap(width, height);var codeGraphics = Graphics.FromImage(codeBitmap);var destRec = new Rectangle(0, 0, width, height);var srcRec = new Rectangle(x, y, width, height);setStatusMsg2(srcRec.ToString());codeGraphics.DrawImage(new Bitmap(screenImagePath), destRec, srcRec, GraphicsUnit.Pixel);// 保留验证码图片codeBitmap.Save(codeImagePath, ImageFormat.Jpeg);// 显示图片picVerifyCode.Load(codeImagePath);picVerifyCode.Tag = codeImagePath;// 验证码辨认var result = BaiduAiSdk.VerifyCode(codeImagePath);if (result.Length > 0) { txtVerifyCode.Text = result; FrmTips.ShowTipsSuccess(this, $"验证码辨认胜利,辨认后果:{result}"); var input = currentBrowser.WebDriver.FindElement(By.XPath("/html/body/spk-root/spk-login-page/div/section/div[3]/div[2]/div[2]/form/div[3]/div[2]/input")); input.Clear(); input.SendKeys(result);} else FrmTips.ShowTipsError(this, "验证码辨认失败,请重试!");参考资料Python +Selenium解决图片验证码登录或注册问题:https://www.mscto.com/python/...python网课主动刷课程序-selenium+chromedriver:https://kaiwu.lagou.com/java_...selenium之 定位以及切换frame/iframe:https://blog.csdn.net/huilan_...Python 爬虫利器五之 Selenium 的用法:https://cuiqingcai.com/2599.html欢送交换程序设计实验室专一于互联网热门新技术摸索与团队麻利开发实际,在公众号「程序设计实验室」后盾回复 linux、flutter、c#、netcore、android、kotlin、java、python 等可获取相干技术文章和材料,同时有任何问题都能够在公众号后盾留言~ ...

February 5, 2021 · 1 min · jiezi

关于c++:洛谷P1451-DFS初学

大抵思路: DFS介绍: 深度优先搜寻(depth-first searching,dfs)优先向深处搜寻,直到无奈找到新的分支时再回溯。因为须要重复地后退、回溯,适宜应用递归来实现。具体地,能够在函数中枚举所有的分支,而后顺次进行递归调用。 #include<bits/stdc++.h> using namespace std; char cell[105][105]; int n,m; void dfs(int i,int j){  cell[i][j]='0';  int dx[4]={1,-1,0,0};  int dy[4]={0,0,1,-1};  for(int k = 0;k < 4;k++){  int xx = i + dx[k],yy = j + dy[k];  if(xx>=0&&xx<n&&yy>=0&&yy<m&&cell[xx][yy]!='0'){  dfs(xx,yy);  }  }  }  int main(){  cin>>n>>m; /* for(int i = 0;i < n;i++)  for(int j = 0;j < m;j++) cin>>cell[i][j]; 开始写的时候没有看输出格局,它是一串一串的,所以不能一个个输出,并且该用char数组而不是int  */   for(int i = 0;i < n;i++)  cin>>cell[i];   int ans = 0;  for(int i = 0;i < n;i++)  for(int j = 0;j < m;j++){  if(cell[i][j] != '0'){  ans++;  dfs(i,j);   }  }  cout<<ans<<endl;  }

February 5, 2021 · 1 min · jiezi

关于c:16-最接近是三数之和

一、双指针法——C语言实现/** * 最靠近的三数和 * LeetCode第16题 * author: aliao language: C*/#include <stdio.h>#include <stdlib.h>int compare (const void *a, const void *b) { return (*(int *)a) - (*(int *)b);}int threeSumClosest(int *nums, int numsSize, int target){ // 先给数组升序排序 qsort(nums, numsSize, sizeof(int), compare); // 定义返回值 int best; for (int i = 0; i < numsSize; i++) { if (i > 0 && nums[i] == nums[i - 1]) { continue; } int head = i + 1; int tail = numsSize - 1; while (head < tail) { // 求和 int sum = nums[i] + nums[head] + nums[tail]; // 将第一个三数之和存为最靠近解best if (i == 0 && head == 1 && tail == numsSize - 1) { best = sum; } // 更新三元素之和 if (abs(sum - target) < abs(best - target)) { best = sum; } if (sum < target) { // 左指针左移 head++; // 左指针去重 while (nums[head] == nums[head - 1]) { head++; } } else if (sum > target) { // 右指针左移 tail--; // 右指针去重 while (nums[tail] == nums[tail + 1]) { tail--; } } else { return target; } } } return best;}int main (void) { int nums[] = {-1, 2, 1, -4}; int numsSize = 4; int target = 1; printf("%d\n", threeSumClosest(nums, numsSize, target));} ...

February 4, 2021 · 2 min · jiezi

关于c++:一文说清-OCLint-源码解析及工作流分析

指标读者一线工程师,架构师 预计浏览工夫15-20min ???? 实现浏览的播种理解动态代码审核技术的原理理解动态代码审核技术工作流不得不提的 Clang因为 OCLint 是一个基于 Clang tool 的动态代码剖析工具,所以不得不提一下 Clang。Clang 作为 LLVM 的子项目, 是一个用来编译 c,c++,以及 oc 的编译器。 OCLint 自身是基于 Clang tool 的,换句话说相当于做了一层封装。它的外围能力是对 Clang AST 进行剖析,最初输入违反规定的代码信息,并且导出指定格局的报告。 接下来就让咱们看看作为输出信息的 Clang AST 是什么样子的。 Clang ASTClang AST 是在编译器编译时的一个两头产物,从词法剖析,语法分析(生成 AST),到语义剖析,生成中间代码。 形象语法树示例这里先对形象语法树有一个初步的印象。 //Example.c#include <stdio.h>int global;void myPrint(int param) { if (param == 1) printf("param is 1"); for (int i = 0 ; i < 10 ; i++ ) { global += i; }}int main(int argc, char *argv[]) { int param = 1; myPrint(param); return 0;} ...

February 3, 2021 · 6 min · jiezi

关于c++:C并发与多线程-5互斥量概念用法死锁演示及详解

互斥量的基本概念临界资源:每次只容许一个线程进行拜访(读/写)的资源线程间的互斥(竞争):多个线程在同一时刻都须要拜访临界资源mutex 类(互斥量)是一把线程锁,保障线程间的互斥 利用线程锁可能保障临界资源的平安互斥量的用法lockmutex.lock() 当锁闲暇时,获取并继续执行当锁被获取时,阻塞并期待锁开释mutex.unlock() 开释锁(同一把锁的获取和开释必须在同一线程中成对呈现)如果 mutex 在调用 unlock() 时处于闲暇状态,那么程序的行为是未定义的 lock_guard在 lock_guard 对象结构时,传入的 mutex 对象(即它治理的 mutex 对象)会被以后线程锁住。在 lock_guard 对象被析构时,它所治理的 mutex 对象会主动解锁,不再须要手动调用 lock 和 unlock 对mutex 进行上锁和解锁操作;lock_guard 对象并不负责 mutex 对象的生命周期,只是简化了上锁和解锁操作;这种采纳“资源分配时初始化”(RAII)办法来加锁、解锁,防止了在临界区中因为抛出异样或return等操作导致没有解锁就退出的问题。这极大的简化了编写mutex相干的异样解决代码。#include <iostream>#include <thread>#include <queue>#include <mutex>using namespace std;class Handle {public: void inMsgRevQueue() { for (int i=0; i<100000; ++i) { m_mutex.lock(); // 留神这里 !!! cout << "inMsgRevQueue() : " << i << endl; m_queue.push(i); m_mutex.unlock(); // 留神这里 !!! } } void outMsgRevQueue() { for (int i=0; i<100000; ++i) { lock_guard<mutex> lck(m_mutex); // 留神这里 !!! if (!m_queue.empty()) { cout << "outMsgRevQueue() : " << m_queue.front() << endl; m_queue.pop(); } } }private: queue<int> m_queue; mutex m_mutex;};int main(){ cout << "main begin" << endl; Handle handler; thread th1(&Handle::inMsgRevQueue, std::ref(handler)); thread th2(&Handle::outMsgRevQueue, std::ref(handler)); th1.join(); th2.join(); cout << "main end" << endl; return 0;}输入: ...

February 2, 2021 · 3 min · jiezi

关于c++:QT5编译使用QFtp

背景应用 QNetworkAccessManager 能够实现 Ftp 的上传/下载性能,但它没有提供例如list、cd、remove、mkdir、rmdir、rename 等性能。这种状况下,咱们能够应用QFtp,须要下载源码、编译并解决一些坑。 下载从 GitHub 下载 QFtp: https://github.com/qt/qtftp编译批改 qftp/qftp.pro,删除最初一行,module_qtftp_tests。不然编译会有谬误,这个是测试子项目,临时去除,先编译应用。批改 qftp/src/qftp/qftp.h 第47行 #include <QtFtp/qurlinfo.h> => #include <qurlinfo.h>批改 qftp/src/qftp/qftp.pro 第4,5行的+,-号调换,生成*.dll批改第4行为 CONFIG += staticlib,生成.lib和.prl用qtcreator关上qftp/qftp.pro,编译生成库文件。 放入QT5装置目录中我以Qt5.5.1为例阐明,其它版本相似 将 Qt5Ftpd.lib、Qt5Ftp.lib、Qt5Ftpd.prl、Qt5Ftp.prl 拷贝至 D:\Qt\Qt5.5.1\5.5\msvc2010\lib。将Qt5Ftpd.dll、Qt5Ftp.dll 拷贝至D:\Qt\Qt5.5.1\5.5\msvc2010\bin。将qftp.h、qurlinfo.h 拷贝至 D:\Qt\Qt5.5.1\5.5\msvc2010\include\QtNetwork,并新建一个名为 QFtp 的文件(没有后缀名),而后用本写入 #include "qftp.h"。运行示例我的项目作为qftp/qftp.pro 我的项目的子项目,间接编译examples我的项目,只须要更改qftp\examples\qftp\ftpwindow.cpp中的43行,将#include <QtFtp>改为#include <QFtp>,即能够编译并运行。作为独立我的项目,除了批改1中的这项,还须要批改qftp\examples\qftp\qftp.pro中ftp库的加载形式,从第五行中删除ftp,而后减少如下代码:CONFIG(debug, debug|release) { LIBS += -lQt5Ftpd} else { LIBS += -lQt5Ftp}也就是说,ftp的加载形式还不能与Qt5的原生库完全一致,如何做到这一点,我还须要工夫钻研。 示例我的项目改良修改进度条的提前显示,对progressDialog新对象进行如下设置,去掉了勾销操作,勾销操作有问题,临时屏蔽。 progressDialog = new QProgressDialog("download...", nullptr, 0, 100, this); progressDialog->setWindowModality(Qt::WindowModal); auto winFlags = windowFlags() & ~Qt::WindowMinMaxButtonsHint; progressDialog->setWindowFlags(winFlags &~ Qt::WindowCloseButtonHint); //去掉窗口的默认按钮 progressDialog->reset(); //防止提前显示 progressDialog->setAutoClose(false); progressDialog->setAutoReset(false);屏蔽勾销按钮的音讯链接。 ...

February 2, 2021 · 1 min · jiezi

关于c++:C并发与多线程-4创建多个线程数据共享问题分析

创立和期待多个线程应用容器类简略治理多个线程。 #include <iostream>#include <thread>#include <vector>using namespace std;void thread_func(int i){ cout << "thread_func id : " << std::this_thread::get_id() << " " << i << endl;}int main(){ cout << "main begin" << endl; vector<thread> threads; for (int i=0; i<10; ++i) threads.emplace_back(thread(thread_func, i)); for (int i=0; i<10; ++i) threads.at(i).join(); cout << "main end" << endl; return 0;}输入:[输入后果每次可能是不统一的,因为子线程间竞争运行未做同步解决] main beginthread_func id : 2 0thread_func id : 3 1thread_func id : 5 3thread_func id : 6 4thread_func id : 4 2thread_func id : 8 6thread_func id : 9 7thread_func id : 7 5thread_func id : 10 8thread_func id : 11 9main end数据共享问题剖析只读多线程只读同一资源是平安的。 ...

February 2, 2021 · 2 min · jiezi

关于c++:C并发与多线程-3线程传参数详解detach-注意事项

获取线程idstd::this_thread::get_id()#include <iostream>#include <thread>using namespace std;std::thread::id main_thread_id = std::this_thread::get_id(); // 留神这里!!!void is_main_thread(){ cout << std::this_thread::get_id() << endl; // 留神这里 !! if (main_thread_id == std::this_thread::get_id()) // 留神这里 !! cout << "This is the main thread" << endl; else cout << "This is not main thread" << endl;}int main(){ is_main_thread(); thread th(is_main_thread); th.join(); return 0;}输入: 1This is the main thread2This is not main thread线程调用对象的参数传递援用作为参数援用作为参数时,产生参数拷贝而不是援用传递;同时应用 std::ref() 与 thread::detach() 时,须要思考主线程中的部分属性资源(对象)是否被子线程应用,并且主线程是否先于子线程完结。 应用 thread::detach() 主线程与子线程拆散独立运行,应用 std::ref() 子线程真正援用所传递实参。当实参在主线程中领有部分属性,并且主线程先于子线程完结,那么主线程实参资源开释,子线程的形参援用便指向未定义的资源,到这里祝贺你,驶入了通向未定义的快车道。C++ 自身有援用(&),为什么又引入 std::ref 呢?次要是思考函数式编程(如 std::thread, std::bind)在应用时,是对参数间接拷贝,而不是援用;std::thread, std::bind 一个函数模板,它的原理是依据已有的模板生成一个函数,然而因为std::thread, std::bind 不晓得生成的函数执行的时候,传递进来的参数是否还无效。所以它抉择参数传递而不是援用传递。如果援用传递,std::ref 和 std::cref 就排上用场了。#include <iostream>#include <thread>using namespace std;void thread_func(const int &i){ cout << "thread_func begin" << endl; cout << "i = " << i << endl; const_cast<int &>(i) = i * 2; cout << "i = " << i << endl; for (int i=0; i<1000; ++i) { } // 操作 obj.i ... cout << "thread_func end" << endl;}int main(){ cout << "main begin" << endl; int i1 = 10; cout << i1 << endl; thread th1(thread_func, i1); // 留神这里 i1 !!! th1.join(); // th1.detach(); // 实参 i1 被拷贝,子线程可失常运行 cout << i1 << endl; cout << "=================" << endl; int i2 = 10; cout << i2 << endl; thread th2(thread_func, std::ref(i2)); // 留神这里 std::ref(i2) !!! th2.join(); // th2.detach(); // 实参被援用,主线程完结时部分 i2 开释, 子线程援用开释资源,行为未定义! cout << i2 << endl; cout << "main end" << endl; return 0;}输入: ...

February 1, 2021 · 4 min · jiezi

关于c++:pika-hash-结构解读

title: pika hash 表 常识总结date: 2021-01-29 13:32:22author: 李朋飞tags: pikacache本文次要对 pika 中 hash 数据结构的应用做一个小结。 <!--more--> pika 是 360 开源的一个非关系型数据库,能够兼容 Redis 零碎的大部分命令。反对主从同步。次要的区别是 pika 反对的数据量不受内存的限度,仅和硬盘大小无关。底层应用了RocksDB 做 KV 数据的存储。本文次要对Pika 的hash 数据结构做个小结。 命令反对接口状态HDEL反对HEXISTS反对HGET反对HGETALL反对HINCRBY反对HINCRBYFLOAT反对HKEYS反对HLEN反对HMGET反对HMSET反对HSET暂不反对单条命令设置多个field value,如有需要请用HMSETHSETNX反对HVALS反对HSCAN反对HSTRLEN反对存储引擎在做数据存储时,pika 会把hash 数据转成一层kv 构造做存储。例如,如果执行如下命令: HSET key field value会首先创立一个 hash 的 meta kv 值,数据格式如下: 为了保留field 和 value 值,将会再创立一个kv,格局如下: 从上图能够看出,每个field 的存储,会存储 整个hash 的key以及key的版本信息。 CRUD操作CU 操作例如 Hset 操作: Status RedisHashes::HSet(const Slice& key, const Slice& field, const Slice& value, int32_t* res) { rocksdb::WriteBatch batch; // 此操作须要加锁 // 函数完结,锁解除 ScopeRecordLock l(lock_mgr_, key); int32_t version = 0; uint32_t statistic = 0; std::string meta_value; // 获取meta 数据 Status s = db_->Get(default_read_options_, handles_[0], key, &meta_value); if (s.ok()) { ParsedHashesMetaValue parsed_hashes_meta_value(&meta_value); if (parsed_hashes_meta_value.IsStale() || parsed_hashes_meta_value.count() == 0) { // 如果meta 存在,然而没有用到 // 则间接更新meta & field & value version = parsed_hashes_meta_value.InitialMetaValue(); parsed_hashes_meta_value.set_count(1); batch.Put(handles_[0], key, meta_value); HashesDataKey data_key(key, version, field); batch.Put(handles_[1], data_key.Encode(), value); *res = 1; } else { // 如果存在,且工夫未过期, 版本正确 version = parsed_hashes_meta_value.version(); std::string data_value; HashesDataKey hashes_data_key(key, version, field); // 获取field 数据 s = db_->Get(default_read_options_, handles_[1], hashes_data_key.Encode(), &data_value); if (s.ok()) { // 如果以后存的field 数据正确 *res = 0; if (data_value == value.ToString()) { // 值也相等,则不操作 return Status::OK(); } else { // 批改kv batch.Put(handles_[1], hashes_data_key.Encode(), value); statistic++; } } else if (s.IsNotFound()) { // 如果没有存在kv, 则增加,并更新meta parsed_hashes_meta_value.ModifyCount(1); batch.Put(handles_[0], key, meta_value); batch.Put(handles_[1], hashes_data_key.Encode(), value); *res = 1; } else { // 获取失败 return s; } } } else if (s.IsNotFound()) { // 若meta 未找到, 编码,写入 char str[4]; EncodeFixed32(str, 1); HashesMetaValue meta_value(std::string(str, sizeof(int32_t))); version = meta_value.UpdateVersion(); batch.Put(handles_[0], key, meta_value.Encode()); HashesDataKey data_key(key, version, field); batch.Put(handles_[1], data_key.Encode(), value); *res = 1; } else { return s; } // 最初批量写 s = db_->Write(default_write_options_, &batch); // 更新总的统计信息 UpdateSpecificKeyStatistics(key.ToString(), statistic); return s;}能够看出,在做HSet 操作时,和料想中一样,会对 metadata 和 field value 同时操作,并须要同时更新,而且须要做锁操作。因为pika是多线程的,在频繁拜访同一个hash中的数据时,会有大量的锁抵触呈现。 ...

February 1, 2021 · 5 min · jiezi

关于c++:在-WebAssembly-中实现回调的方式

本文将介绍在 C++ 中实现 js 回调的几种形式. 在应用 wasm 的过程中, 防止不了要从 C++ 回调 js 的函数来实现异步交互.官网文档 https://emscripten.org/docs/p...中曾经介绍了6种实现回调的形式, 这里介绍几种能解决理论问题的形式。 EM_ASM 相干参数介绍EM_ASM 函数簇蕴含 EM_ASMEM_ASM_INTEM_ASM_DOUBLE相似的应用形式 : EM_ASM_({ postMessage({cmd: 'callback', text: "callback", threadId: $2, callId : $0, code : $1}) }, callback, code, tid);其中&dollar;0&dollar;1&dollar;2别离代表 callback, code, tid 的值.前面两个函数还能够获取到 js 返回的 int/ double 值. 个别能满足简略的应用. 如何在 worker 中实现回调应用 wasm 的时候, 某些工作会被放到 worker 中执行, 执行实现后回调告诉后果. 这个时候要特地留神: worker 和主线程是互相独立的, 并不能像一般的多线程能够共享过程内的数据. 在 worker 中调用 js 回调时, 第一个面临的限度就是 web worker 的限度: 不能拜访 window, document 对象与主线程通信须要通过 post message 形式不能拜访主过程中的全局变量会对象如果间接在 worker 中间接调用回调, 就只能做一些简略的事件. 为此 emscripten 提供了以下函数: ...

February 1, 2021 · 1 min · jiezi

关于c#:一篇文章教你如何使用第三方控件构建多步向导界面

点击获取工具>> 利用好的界面控件,往往能做成比拟界面体验成果。在一些界面操作外面,咱们可能把它拆分为几部进行解决,这个时候引入WizardControl向导控件应该是比拟不错的抉择了。多步的解决形式,能够让用户防止一次性输出太多内容的焦躁情绪,也能够针对性的校验局部内容,本文以利用WizardControl控件来设计找回明码的后果来进行介绍,使大家对基于DevExpress的WizardControl向导控件的应用有一个大略的理解。 一、界面成果的布局在个别APP或者基于网络的软件界面外面,都有一个为了帮忙用户找回账号密码的性能,能够让用户自助通过手机、邮件等形式取得充值明码的机会。如个别的APP界面成果如下所示。 然而个别Winform的界面,能够利用向导控件做的更好,其中DevExpress的WizardControl向导控件就是一个很好的抉择。 咱们个别在DevExpress的VS工具栏外面抉择导航布局选项卡,就能够找到对应的WizardControl向导控件了。 最终咱们实现的成果如下所示。 二、控件的应用及代码解决下面介绍了,在在DevExpress的VS工具栏外面抉择导航布局选项卡,就能够找到对应的WizardControl向导控件了。 咱们拖动能这个控件到一个空白的窗体界面上,就能够看到默认有一些界面了,咱们在其中能够看到一个残缺的向导界面成果的。 拖动过去的控件,初始化界面成果都是英文的,能够通过控件属性对其中的文字进行批改即可。 批改后的界面成果如下所示。 而后咱们批改向导控件的一些属性,如图片、文字等内容,最初在其中空白的地位,拖入一些界面控件,实现咱们的界面成果即可。 另外默认的向导控件是三个界面页的,因而咱们能够依据须要减少或者删除一些,如本例我就移除了一个,仅仅应用两个页面来解决明码的找回解决即可。 另外,咱们为了实现向导控件界面的输出验证和解决,咱们往往还须要对其中下一步、实现、勾销、帮忙等事件进行解决,这样能力达到较好的解决成果。 其中局部解决代码如下所示。 private void wizardControl1_NextClick(object sender, DevExpress.XtraWizard.WizardCommandButtonClickEventArgs e){string pageText = e.Page.Text;if(pageText == "验证账号"){if (this.txtMobile.Text.Length == 0 || this.txtValidateCode.Text.Length == 0){MessageDxUtil.ShowTips("请输出手机号码和验证码");e.Handled = true;this.txtValidateCode.Focus();return;}else if(!ValidateUtil.IsValidMobile(this.txtMobile.Text)){MessageDxUtil.ShowTips("请输出正确的手机号码");e.Handled = true;this.txtMobile.Focus();return;}else{bool result = CallerFactory<ISmsCodeService>.Instance.CheckSmsCode(this.txtMobile.Text, this.txtValidateCode.Text);if (!result){MessageDxUtil.ShowTips("验证码校验不正确,请查看验证码是否在无效工夫内。");this.txtValidateCode.Focus();return;e.Handled = true;}}}else if(pageText == "重置明码"){MessageDxUtil.ShowTips(pageText);}} 在这些Next下一步事件外面,有一个代码是须要阻塞下一步的解决的。 e.Handled = true; 这样咱们就能够实现对用户输出的验证解决了,如果解决不通过,那么就停留在这个页面上,让用户校对输出即可。 如果是实现按钮页面,它的解决也是差不多。 private void wizardControl1_FinishClick(object sender, CancelEventArgs e){if (this.txtCorpAccount.Text.Length == 0){this.txtCorpAccount.Focus();MessageDxUtil.ShowTips("公司账号不能为空!");e.Cancel = true;return;}else if(this.txtNewPassword.Text.Length == 0){this.txtNewPassword.Focus();MessageDxUtil.ShowTips("明码不能为空!");e.Cancel = true;return;}else if (!this.txtNewPassword.Text.Equals(this.txtRePassword.Text)){this.txtRePassword.Focus();MessageDxUtil.ShowTips("两次明码不统一!");e.Cancel = true;return;} ...

February 1, 2021 · 1 min · jiezi

关于c:递归的解读

前沿递归的思维是软件思维的根本思维之一,在树和图下面,简直全是用递归来实现的。计算机特地适宜用递归的思维来解决问题,然而咱们人类用递归的思维来思考问题就会感到非常困扰。接下来咱们一起探索递归吧。 定义一个函数本人间接或者间接调用本人 注:一个函数调用另外一个函数和他调用本人都是截然不同的。 递归满足的三个条件: 递归必须有一个明确的终止条件该函数解决的数据规模必须在递加这个转化必须时可解的函数的调用当在一个函数的运行期间调用另外一个函数时,在运行被调用函数之前,零碎须要实现三件事 将所有的理论参数,返回地址等信息传递给被调用函数。为被调用函数的局部变量(也包含形参)调配存储空间。将管制转移到被调用函数的入口。从被调函数返回主调函数之前,零碎也要实现三件事 保留被调函数的返回后果开释被调函数所占的存储空间按照被调函数保留的返回地址将管制转移到调用函数当有多个函数互相调用时,依照“后调用先返回”的准则 上诉函数之间信息传递和管制转移必须借助 “栈” 来实现,即零碎将整个程序运行所需的数据空间安顿在一个栈中,每当调用一个函数时,将在栈顶调配一个存储区,进行压栈操作,每当一个函数退出时,就开释它的存储区,就进行出栈操作,以后运行的函数永远都在栈顶地位。 算法咱们来看一题比拟经典的面试题,大家能够本人猜想下运算后果 #include <iostream>#include <cstdlib>int f(int num){ printf("%d\n", num); if (num <= 1) { return 1; } f(num-1); printf("%d\n", num); return 0;}int main() { f(3); return 0;}这道题目后果会是什么呢?他到底是怎么调用的呢? 我来画个调用图 咱们关注红色的调用箭头 首先运行主函数的f(3)而后调用 int f(3) 打印出 3而后调用 int f(2) 打印出 2而后调用 int f(1) 打印出 1,而后满足条件 return 1;完结 int (f1)之后回到 int f(2) 打印出 2之后回到 int f(3) 打印出 3最初回到主函数,程序完结所以最初打印的数是 3 2 1 2 3 ...

January 31, 2021 · 1 min · jiezi

关于c++:C并发与多线程-2线程启动结束创建线程多种方法joindetach

演示线程运行的开始和完结可执行程序运行失去一个过程,过程中惟一的主线程启动,当主线程从 main 函数返回,整个进行完结。创立的子线程须要从一个初始函数开始运行,一旦函数执行结束,以后子线程完结。过程完结标记:主线程是否完结。如果主线程执行结束,则代表整个过程完结,个别状况下此时如果还有其它子线程未执行完,则子线程会被强行终止(例外:detach)。thread创立一个线程执行对象。 join阻塞主线程(调用线程),直到子线程执行完结。 注:须要保障在 joinable 返回 true 时应用(返回 false 时运行时抛出 std::system_error 异样)detach将子线程和主线程的关联拆散,子线程可驻留零碎后盾独立持续运行,主线程无奈再取得主线程的控制权,即主线程完结,子线程也不会完结。当子线程完结时,由C++运行时库负责清理线程相干的资源。 注:须要保障在 joinable 返回 true 时应用(返回 false 时运行时抛出 std::system_error 异样)joinable判断一个线程对象是否可能调用 join() 或者 detach(),能够返回 true,不能够返回 false。 Test1: thread, join, joinable #include <iostream>#include <thread>using namespace std;void thread_func(){ cout << "thread_func begin" << endl; for (uint32_t i=0; i<10000; ++i) { } cout << "thread_func end" << endl;}int main(){ cout << "main begin" << endl; thread my_thread(thread_func); if (my_thread.joinable()) // 注: 调用 join 前须要 joinable 判断!!! { cout << "my_thread.joinable() " << my_thread.joinable() << endl; my_thread.join(); } cout << "my_thread.joinable() " << my_thread.joinable() << endl; cout << "main end" << endl; return 0;}输入: ...

January 31, 2021 · 3 min · jiezi

关于c++:C程序性能优化指南

准则《More Effective C++》书中效率局部第一条就是80—20准则。说得是——大概 20%的代码应用了 80%的程序资源;大概 20%的代码耗用了大概 80%的运行工夫;大概 20%的代码应用了 80%的内存。因而,一些简略的优化也能显著进步程序性能。先实现程序性能,再思考性能优化的事,否则会呈现代码可读性差,适度形象等问题。大部分的性能优化其实都是在做工夫和空间的衡量,空间换工夫,或者工夫换空间。良好的代码格调和代码标准能无效的防止性能问题的呈现,所以codereview也很重要。咱们真正想大幅度的晋升程序性能须要借助程序分析器(profiler)寻找出程序的性能瓶颈,针对这个瓶颈进行代码层面,算法层面,架构层面等多方面的优化。罕用优化办法空间足够时,能够将常常须要读取的资源,缓存在内存中。尽量减少大内存对象的结构与析构,思考缓存临时不必的对象,期待后续持续应用。尽量应用C++11的右值语义,缩小长期对象的结构。简略的性能函数能够应用内联。少用继承,多用组合,尽量减少继承层级。在循环遍历时,优化判断条件,缩小循环次数。优化线程或过程的同步形式,能用原子操作的就不必锁。能应用层同步的就不必内核对象同步。优化堆内存的应用,如果有内存频繁的申请与开释,能够思考内存池。优化线程的应用,节俭系统资源与切换造成的性能损耗,线程应用频繁的能够思考线程池。尽量应用事件告诉,审慎应用轮循或者sleep函数。界面开发中,耗时的业务代码不要放在UI线程中执行,应用独自的线程去异步解决耗时业务,进步界面响应速度。常常重构、优化代码构造。优化算法或者架构,从设计层面进行性能的优化。

January 31, 2021 · 1 min · jiezi

关于c++:C并发与多线程-1并发基本概念及实现进程线程基本概念

并发、过程、线程的基本概念和综述并发两个或者更多的工作(独立的流动)同时产生(进行):一个程序同时执行多个独立的工作。以往计算机为单核CPU(中央处理器):某一时刻只能执行一个工作,由操作系统调度,每秒钟进行屡次“工作切换”,这并不是真正的并发。同时工作切换须要保留与复原工作上下文,存在工夫开销。随着硬件倒退,呈现了多处理器(多核)计算机,可能实现真正的并行任务解决(硬件并发)。应用并发的起因:能够同时解决多个工作,进步解决性能。 可执行程序磁盘上的一个文件: window : .exelinux :具备可执行属性的文件 (-x)过程运行一个可执行程序失去过程。过程是操作系统资源分配的根本单位。线程每个过程都有一个惟一的主线程。过程被创立时,主线程启动执行 main 函数。线程中能够持续创立其它非主线程。线程是操作系统调度的根本单位。 学习心得开发多线程程序是商用的必须需要。线程开发有肯定难度。C++线程会设计到很多新的概念。网络通讯、网络服务中多线程是肯定会被用到的。并发的实现办法通过多个过程实现并发。在独自的过程中,写代码创立除了主线程之外的其它线程实现并发。 多过程并发例:启动word和网页浏览器同时解决不同工作。过程之间的通信形式 同一电脑:管道、文件、音讯队列、共享内存、socket通信不同电脑:socket 通信多线程并发每个线程可有本人独立的运行门路同一过程中所有线程共享地址空间(共享内存)。全局变量、指针、援用等能够在线程之间传递,通信开销远远小于过程。线程并不是越多越好,线程须要独立的堆栈空间,同时线程切换时会耗费执行工夫。总结多过程并发和多线程并发能够混合应用,但倡议优先思考多线程技术。C++11 新规范线程库经典开发方式 indow: CreateThread(), _beginthread(),_beginthreadexe()linux : pthread_create();posix thread (跨平台,须要最根底配置)C++11及后续 语言层面反对多线程,意味着可跨平台,缩小开发人员工作两。

January 31, 2021 · 1 min · jiezi

关于c#:Unity面向新手超简单的UI框架

前言揭示:为了可能将知识点学得更加透彻、记得更加牢固 我会通过教学解说的形式把常识写下来 因为在过程中会让人从学生变成老师 这个过程会开掘出新的常识和观点 是一个自我思维切换而达成的常识深度开掘和晋升的过程 如果能帮忙到大家那就最好 如果有讲错的中央还请多多指教!我只是一只菜鸡 感激了解! 为什么要应用UI框架游戏中存在十分多的面板 例如:背包面板、商店面板、设置面板、 这些面板之间会须要频繁的调用和切换,例如:背包面板中存在各种物品,咱们鼠标放到物品上会呈现物品信息的提示框,还有设置面板须要按返回键才能够切换回主菜单面板,那咱们如何实现界面间的沟通呢?我之前的做法就是在每个我要用到的面板上都写一个脚本实现对应的性能,置信不少老手开发者都是这样过去的吧。(纳尼菜逼竟是我本人?) 尽管这样做性能是实现了,然而维护性升高了、反复的代码也变多了,为了更加不便的治理和调用场景中的面板 咱们须要写一套残缺的框架来对它们进行束缚不然很容易呈现面板共存,或者切换失败等问题。 恰好SIKI老师有一套面向老手的小型UI框架课程讲得蛮好的,最重要的是简略啊!!! 对我这种老手来说真的十分敌对!咱们一起来学习下吧! 框架的思路先来简略介绍下这个框架的思路吧 ,框架次要实现了面板的读取存储和治理,帮忙咱们更好的进行面板之间的切换治理 首先1、咱们通过Json文件存储咱们所有要用到的面板信息 例如:面板的名字 面板的类型 面板的加载门路 等等,按理论我的项目需要为准 2、创立一个面板抽象类(就是所有面板的基类)来实现面板共有的一些办法,比方面板进入的时候要做的一些事件,面板退出时候要做的一些事件 3、通过代码读取Json文件失去所有面板的信息,而后咱们就能通过这些信息来操作面板 4、框架最外围的中央就是如何高效的治理这些面板 先来走一遍咱们面板的生成和敞开的流程 此时玩家只能操作背包面板,无奈操作人物面板(想想是不是很多游戏都是这样)当咱们想要操作人物面板的时候 咱们须要先敞开背包面板而后能力操作人物面板 这里再画一幅图来解释 当初咱们位于最下面的设置菜单中子菜单界面,此时咱们只能操作子菜单界面,如果咱们想操作设置菜单界面的话 咱们须要先敞开子菜单,能力操作设置菜单 当初子菜单敞开了,咱们就能够操作设置菜单了! 同理如果咱们想操作主菜单 那咱们就必须要敞开设置菜单能力去操作主菜单 所以Siki老师是如何治理面板之间切换关系的呢?理解过数据结构的同学看了下面的图可能马上就懂了!对的就是用堆栈(Stack)来实现 ,堆栈是一个后进先出的对象汇合 后进先出 先进后出?这不恰好能够用来存储管理咱们的面板吗 先进后出 最先进入的是主菜单,所以咱们把他放到了容器底部,而后玩家又点击了设置菜单,于是咱们把他放到主菜单的下面,而后玩家又点击了设置菜单里的子菜单,咱们把子菜单放到了设置菜单的下面 咱们让玩家只能操作栈中的顶部面板,通过Push把面板入栈(面板进入) 通过Pop把顶部面板出栈(面板退出) 这样就轻松实现了面板之间的切换性能了 好吧说实话我感觉我讲的是一坨屎(可能只有我本人能听懂 举荐间接去看Siki老师讲的) 实操思路理了一下!当初咱们一步一步来做吧! 1、创立Json文件,把面板信息写入到Json中首先咱们来实现第一步 咱们通过Json文件存储咱们所有要用到的面板信息 例如:面板的名字 面板的类型 面板的加载门路 等等,按理论我的项目需要为准 在创立Json文件之前,咱们须要先把要用到的面板做成预制体寄存到Resources门路下稍后通过Resources来加载这些咱们要用到的面板,这里我本人新建了一张图作为面板来演示,命名为“SettingPanel”寄存到Resources的UIPanel文件夹下 好当初咱们就来创立一个Json文件(新建一个文本文件 后缀改成.Json就是一个Json文件了,留神咱们Json文件也要放到Resources文件夹下因为咱们稍后会通过Resources来获取它) 并往里面写上咱们面板的信息,这里为了不便小伙伴们的了解我就写简略一点 json文件 { "data": [ {"uiPanelType":"settingPanel","uiPanelPath":"UIPanel/SettingPanel"} ]}这里简略讲下Json文件的格局吧 花括号{} 保留对象:对象能够蕴含各种数据,包含数组。方括号[] 保留数组:数组能够蕴含对象。数据由逗号分隔 ...

January 31, 2021 · 5 min · jiezi

关于c:进程之间的关系

简介:这解说过程之间的关系:父子过程、过程和过程组、会话。这节只须要理解即可。 1: 首先、解说一下终端登录。 在晚期的时候、咱们应用终端设备进行登录,然而因为终端设备连贯的无限,因而登录的用户也就是无限的。随着位映射图形终端变得可用,开发出了窗口零碎,它向用户提供了与主机零碎进行交互的新形式。在这里、我简略介绍一下过来有终端设备登录的流程(只是做为一个理解)。首先是init过程读取/etc/ttys文件(此文件保留各个终端设备的信息),为每一个终端创立一个空的环境。而后应用getty函数以读写的形式关上终端,并将规范输出、输入和谬误重置到该终端中,最初执行login程序进行登录。2:这里简略介绍一下过程组的概念。 每一个过程都属于一个过程组,每个过程组有相似与过程ID的过程组ID。过程组的存在不便咱们管理控制。在上一节中、咱们介绍回收过程的时候,能够期待指定过程组ID中的过程完结。有些时候,咱们可能须要很多个过程单干去实现某一项工作。这时候,咱们能够应用过程组的概念去会后过程组中的过程。上面我简略列举一个例子。多过程服务器:每当一个客户端到来的时候、咱们创立一个新的过程去执行相应的工作。当执行完工作后,子过程就会向父过程发送终止信号,这时候、我峨嵋你不分明是该过程组中的那个过程完结了。因而、咱们能够抉择去回收该过程组中的过程。咱们能够应用如下函数获取和设置过程ID。int setpgid(pid_t pid, pid_t pgid);此函数用于将指定过程ID设置为pgid,然而这个函数只能为本人或者对应的子过程设置过程组ID,同时、如果子过程应用了exec函数后就不能设置过程组ID。如果你想要父子过程同属一个过程组,那么请在fork之后应用此函数设置过程组ID。int getpgid(pid_t pid);获取指定过程ID的过程组ID。注:只有过程组中有一个过程存在,那么该过程组就存在。(因而、在这里咱们感觉过程组ID是这过程创立终止而随时变动的。3:会话 会话的概念倒是非常简略、他就是几个过程组的汇合。会话是没有会话ID的,通常咱们能够取得该过程的首个过程组的过程组ID。通常状况下、咱们能够fork一个子过程去调用如下的函数以保障改过程和其余过程没有什么关系(除了、父过程是init过程)。pid_t setsid(void);将调用该函数的过程设置为一个会话。在调用此函数后、改过程会产生如下状况。a)改过程成为一个会话的首过程。b)该过程是一个新的过程组的组长过程。c)如果改过程之前和管制终端有分割的话,那么当初改过程和管制终端将不会有什么分割。pid_t getsid(pid_t pid);此函数用于获取指定过程所处会话首个过程组的过程组ID。4:管制终端。 会话和过程组有一些其余的恶行:a:一个会话能够有一个管制终端。这通常是登录到其余的终端设备或伪终端设备。b:建设与管制终端连贯的过程称为伪终端过程。c:一个会话中能够分为前台过程组和后盾过程组。d:如果一个会话有一个管制终端,则它有一个前台过程组,会话中的其余过程组则为后盾过程组。e:信号会发送给前台过程组。如下两个函数用于告诉内核哪一个是前台过程组。pid_t tcgetpgrp(int filedes);//用于将filedes先关联的终端设备前台过程组的过程组ID。

January 31, 2021 · 1 min · jiezi

关于c:函数运行时在内存中是什么样子

在开始本篇的内容前,咱们先来思考几个问题。 咱们先来看一段简略的代码:void func(int a) { if (a > 100000000) return; int arr[100] = {0}; func(a + 1);}你能看出这段代码会有什么问题吗? 咱们在之前的文章《高性能高并发服务器是如何实现的》一中提到了一项关键技术——协程,你晓得协程的实质是什么吗?有的同学可能会说是用户线程,那么什么是用户态线程,这是怎么实现的?函数运行起来后是什么样子?这个问题看似没什么关联,但这背地有一样货色你须要了解,这就是所谓的函数运行时栈,run time stack。 接下来咱们就好好看看到底什么是函数运行时栈,为什么彻底了解函数运行时栈对程序员来说十分重要。 从过程、线程到函数调用汽车在高速上行驶时有很多信息,像速度、地位等等,通过这些信息咱们能够直观的感触汽车的运行时状态。 同样的,程序在运行时也有很多信息,像有哪些程序正在运行、这些程序执行到了哪里等等,通过这些信息咱们能够直观的感触零碎中程序运行的状态。 其中,咱们发明了过程、线程这样的概念来记录有哪些程序正在运行,对于过程和线程的概念请参见《看完这篇还不懂过程和线程你来打我》。 过程和线程的运行体现在函数执行上,函数的执行除了函数外部执行的程序执行还有子函数调用的管制转移以及子函数执行结束的返回。其中函数外部的程序执行乏善可陈,重点是函数的调用。 因而接下来咱们的视角将从宏观的过程和线程拉近到宏观下的函数调用,重点来讨论一下函数调用是怎么实现的。 函数调用的流动轨迹:栈玩过游戏的同学应该晓得,有时你为了实现一项主线工作不得不去打一些干线的工作,干线工作中可能还有干线工作,当一个干线工作实现后退回到前一个干线工作,这是什么意思呢,举个例子你就明确了。 假如主线工作西天取经A依赖干线工作收服孙悟空B和收服猪八戒C,也就是说收服孙悟空B和收服猪八戒C实现后能力持续主线工作西天取经A; 干线工作收服孙悟空B依赖工作拿到紧箍咒D,只有当工作D实现后能力回到工作B; 整个工作的依赖关系如图所示: 当初咱们来模仿一下工作实现过程。 首先咱们来到工作A,执行主线工作: 执行工作A的过程中咱们发现工作A依赖工作B,这时咱们暂停工作A去执行工作B: 执行工作B的时候,咱们又发现依赖工作D: 执行工作D的时候咱们发现该工作不再依赖任何其它工作,因而C实现后咱们能够会退到前一个工作,也就是B: 工作B除了依赖工作C外不再依赖其它工作,这样工作B实现后就能够回到工作A: 当初咱们回到了主线工作A,依赖的工作B执行实现,接下来是工作C: 和工作D一样,C不依赖任何其它其它工作,工作C实现后就能够再次回到工作A,再之后工作A执行结束,整个工作执行实现。 让咱们来看一下整个工作的流动轨迹: 仔细观察,实际上你会发现这是一个First In Last Out 的程序,人造实用于栈这种数据结构来解决。 再认真看一下栈顶的轨迹,也就是A、B、D、B、A、C、A,实际上你会发现这里的轨迹就是工作依赖树的遍历过程,是不是很神奇,这也是为什么树这种数据结构的遍历除了能够用递归也能够用栈来实现的起因。 A box函数调用也是同样的情理,你把下面的ABCD换成函数ABCD,实质不变。 因而,当初咱们晓得了,应用栈这种构造就能够用来保留函数调用信息。 和游戏中的每个工作一样,当函数在运行时每个函数也要有本人的一个“小盒子”,这个小盒子中保留了函数运行时的各种信息,这些小盒子通过栈这种构造组织起来,这个小盒子就被称为栈帧,stack frames,也有的称之为call stack,不论什么命名形式,总之,就是这里所说的小盒子,这个小盒子就是函数运行起来后占用的内存,这些小盒子形成了咱们通常所说的栈区。对于栈区具体的解说你能够参考《深刻了解操作系统:程序员应如何了解内存》一文。 那么函数调用时都有哪些信息呢? 函数调用与返回信息咱们晓得当函数A调用函数B的时候,管制从A转移到了B,所谓管制其实就是指CPU执行属于哪个函数的机器指令,CPU从开始执行属于函数A的指令切换到执行属于函数B的指令,咱们就说管制从函数A转移到了函数B。 管制从函数A转移到函数B,那么咱们须要有这样两个信息: 我从哪里来 (返回)要到去哪里 (跳转)是不是很简略,就好比你进来游览,你须要晓得去哪里,还须要记住回家的路。 函数调用也是同样的情理。 当函数A调用函数B时,咱们只有晓得: 函数A对于的机器指令执行到了哪里 (我从哪里来,返回)函数B第一条机器指令所在的地址 (要到哪里去,跳转)有这两条信息就足以让CPU开始执行函数B对应的机器指令,当函数B执行结束后跳转回函数A。 ...

January 31, 2021 · 1 min · jiezi

关于c:C语言实现随机抽取纸牌

利用数组实现从一副牌中随机抽取纸牌,供大家参考,具体内容如下一、我的项目要求本程序负责发一副规范纸牌,每张规范纸牌都有一种花色(梅花、方块、黑桃、红桃)和一个等级(2,3,4,5,6…K,A)。程序须要用户指明手机有几张牌,格局为:Enter number of cards in hand:____your hand: _二、原理1.应用库函数time函数返回以后工夫,用一个数示意,srand函数初始化C语言的随机数生成器。通过把time函数返回值传递给srand能够防止程序每次运行发同样的牌。rand函数产生随机数,通过%缩放。2.利用二维数组记录程序采纳in_hand二维数组对曾经抉择的牌进行记录,4行示意每种花色,13列示意每种等级。程序开始时,数组元素都为false,每随机抽取一张纸牌时,查看in_hand对应元素虚实,如果为真,则抽取其余纸牌,如果为假,记录到数组元素当中,揭示咱们这张牌曾经记录过了站长博客。三、我的项目代码我的项目的具体代码展现如下: include <stdio.h>include <ctype.h>include <stdbool.h>include <time.h>include <stdlib.h>define num_rates ((int) (sizeof(value)/sizeof(value[0])))define initial_balance 100.00define num_suits 4define num_ranks 13int main(){ bool in_handnum_suits = {false};int num_cards,rank,suit; const char rank_code[] = { '2','3','4','5','6','7','8','9', 't','j','q','k','a'};const char suit_code[] = { 'c','d','h','s'};printf("enter numbern");scanf("%d",&num_cards); printf("your handsn");while(num_cards>0){ suit = rand()%num_suits; rank = rand()%num_ranks; if(!in_handsuit){ in_handsuit = true; num_cards--; printf(" %c%c",rank_code[rank],suit_code[suit]); }}printf("n");return 0;}

January 30, 2021 · 1 min · jiezi

关于c++:C中控制远程计算机的服务的方法

在.net中提供了一些类来显示和管制Windows零碎上的服务,并能够实现对近程计算机服务服务的拜访,如System.ServiceProcess命名空间上面的ServiceController 类,System.Management上面的一些WMI操作的类。尽管用ServiceController能够很不便的实现对服务的管制,而且很直观、简洁和容易了解。然而我认为他的性能同通过WMI来操作服务相比,那可能就有些繁多了,并且对多个服务的操作可能就比拟麻烦,也无奈列出零碎中的所有服务的具体数据。这里要讲的就是如何应用System.Management组件来操作近程和本地计算机上的服务。 WMI作为Windows 2000操作系统的一部分提供了可伸缩的,可扩大的治理架构.公共信息模型(CIM)是由分布式治理工作规范协会(DMTF)设计的一种可扩大的、面向对象的架构,用于管理系统、网络、应用程序、数据库和设施。Windows治理标准也称作CIM for Windows,提供了对立的拜访治理信息的形式。如果须要获取具体的WMI信息请读者查阅MSDN。System.Management组件提供对大量治理信息和治理事件汇合的拜访,这些信息和事件是与依据 Windows 治理标准 (WMI) 构造对系统、设施和应用程序设置检测点无关的。 然而站长博客下面并不是咱们最关怀的,上面才是咱们须要谈的话题。 毫无疑问,咱们要援用System.Management.Dll程序集,并要应用System.Management命名空间下的类,如ManagementClass,ManagementObject等。上面用一个名为Win32ServiceManager的类把服务的一些相干操作包装了一下,代码如下: using System; using System.Management; namespace ZZ.Wmi { public class Win32ServiceManager { private string strPath; private ManagementClass managementClass; public Win32ServiceManager():this(".",null,null) { } public Win32ServiceManager(string host,string userName,string password) { this.strPath = "\\"+host+"\root\cimv2:Win32_Service"; this.managementClass = new ManagementClass(strPath); if(userName!=null&&userName.Length>0) { ConnectionOptions connectionOptions = new ConnectionOptions(); connectionOptions.Username = userName; connectionOptions.Password = password; ManagementScope managementScope = new ManagementScope( "\\" +host+ "\root\cimv2",connectionOptions) ; this.managementClass.Scope = managementScope; } } // 验证是否能连贯到近程计算机 public static bool RemoteConnectValidate(string host,string userName,string password) { ConnectionOptions connectionOptions = new ConnectionOptions(); connectionOptions.Username = userName; connectionOptions.Password = password; ManagementScope managementScope = new ManagementScope( "\\" +host+ "\root\cimv2",connectionOptions) ; try { managementScope.Connect(); } ...

January 30, 2021 · 1 min · jiezi

关于c#:C语言特性及发展史

本文依照C#语言的倒退历史,介绍C#每个版本的新增个性,次要参考微软官网文档。理解这些语言个性能够帮忙咱们更高效的编写C#代码。 C# 1.0与Visual Studio .NET 2002一起公布,该版本的C#十分像Java。 类构造接口事件属性委托运算符和表达式语句个性:无效地将元数据或申明信息与代码相关联,从而在运行时应用反射查问个性C# 1.2随Visual Studio .NET 2003一起公布,次要是一些小改良。值得注意的是,从此版本开始,当IEnumerator实现IDisposable时,foreach循环中生成的代码会在IEnumerator上调用Dispose。 C# 2.0与Visual Studio 2005一起公布。自2.0开始,C#打好了根底,开始谋求解决一些重大影响开发者的难点。 泛型:应用泛型优于创立派生自ArrayList的ListInt或强制转换形式partial class匿名办法:delegate运算符创立一个能够转换为委托类型的匿名办法。从C# 3.0开始,可应用lambda表达式创立匿名办法。可空类型:可空类型T?示意其根底类型T的所有值及额定的null值。迭代器:容许应用foreach来查看List(或其它可枚举类型)中的所有项协变和逆变:实现数组类型、委托类型和泛型类型参数的隐式援用转换C# 3.0与Visual Studio 2008一起公布,但残缺性能是在.NET Framework 3.5版本中公布的。此版本标记着C#倒退过程中的重大更改。 主动实现的属性:C# 6及更高版本可像字段一样对其初始化匿名类型查问表达式lambda表达式表达式树扩大办法:无需创立派生类、从新编译或其它形式即可向现有类型增加办法varpartial method:partial class的一部分定义签名,一部分定义实现对象汇合初始化语法:new后应用{}进行初始化C# 4.0随Visual Studio 2010一起公布。 动静绑定:dynamic关键字命名参数/可选参数:命名参数指定参数实参,不需匹配参数列表地位泛型协变和逆变嵌入互操作类型:CLR反对将COM类型信息间接嵌入到托管程序集中,不要求托管程序集从互操作程序集中获取COM类型的类型信息,弛缓了部署难点C# 5.0随Visual Studio 2012一起公布,次要工作是实用于异步编程的async和await模型。 异步成员:语言级别的异步编程模型,外围是Task和Task<T>对象,承受关键字async和await的反对调用方信息个性C# 6.0随Visual Studio 2015一起公布。 动态导入:using static指令when:用于catch语句和switch语句主动属性初始化表达式:属性的get/set拜访器可应用=>简化语法=>运算符Null流传器:仅当操作数的计算结果为非null时,null条件运算符才会将成员拜访?.或元素拜访?[]运算利用于其操作数,否则返回null字符串内插:$特殊字符将字符串文本标识为内插字符串nameof运算符C# 7.0与Visual Studio 2017一起公布。 out变量:能够在办法调用的参数列表中申明out变量,无需独自编写申明语句元组和析构函数:能够创立蕴含多个公共字段的轻量级未命名类型模式匹配:反对is表达式和switch表达式。is模式表达式可在一条指令调配后果:input is int count本地函数:实用于迭代器办法和异步办法,在办法外部申明办法扩大expression bodied成员:可在属性、索引器、结构、析构、get/set拜访器应用=>ref局部变量和返回后果throw表达式:throw可作为表达式而不是语句C# 7.1 7.2 7.3此版本开始C#能够单点发行,编译器有-refout和-refonly两个选项,可用于管制援用程序集生成。 async Main办法:可在Main办法中应用await关键字default文本表达式启用更高效的平安代码private protected拜访修饰符条件ref表达式:条件表达式?:的援用而不是值无需固定即可拜访固定的字段能够重新分配ref本地变量能够应用stackalloc数组上的初始值设定项能够对反对模式的任何类型应用fixed语句能够应用其余泛型束缚C# 8.0专门面向.NET Core的第一个次要C#版本。 readonly成员:可将readonly修饰符用于struct成员默认接口办法:可将成员增加到接口并提供实现模式匹配加强性能:在更多地位应用,联合switch表达式(不是switch语句),可用于属性模式、元组模式、地位模式using申明:带using关键字的变量申明,批示编译器在关闭范畴的开端解决变量动态本地函数可处理的ref构造可空援用类型异步流:创立并以异步形式应用流索引和范畴:为拜访序列中的单个或范畴元素提供了简洁语法。依赖两个新运算符:开端运算符^和范畴运算符..null合并赋值:仅当左操作数为null时,能力应用??=运算符将右操作数赋给左操作数非托管构造类型嵌套表达式中的stackalloc内插逐字字符串的加强性能:$和@程序可任意安顿C# 9.0.NET 5.0反对C# 9.0 record类型:不可变的援用类型,应用值语义实现相等性仅限init的资源库:可为属性和索引器创立init拜访器而非set拜访器,结构完变为只读顶级语句:应用程序中只有一个文件可应用顶级语句模式匹配加强性能:and/or/not,如if (e is not null) ...性能和互操作性调整和实现性能:如在new表达式中省略类型:private List<int> nums = new();反对代码生成器

January 30, 2021 · 1 min · jiezi

关于c++:struct关键字与class关键字区别

惟一的区别:默认成员拜访说明符及默认派生拜访说明符。struct:默认public(私有)class:默认private(公有)

January 30, 2021 · 1 min · jiezi

关于c++:mac-vscode-c-环境配置编译debug

官网中对应的页面如下 https://code.visualstudio.com... 1 筹备vscode 软件C/C++ Extension Pack 插件 clang/clang++ 编译器 查看已装置clang++ clang++ -v如果未装置,请返回 app store 下载 xcode2 .vscode配置在当前工作区筹备以下文件(夹) .vscode tasks.json # 用于编译c++文件launch.json # 用于应用vscode自带的debug工具(左侧的小虫图标)c_cpp_properties.json # 用于应用vscode自带的代码提醒工具如 IntelliSensemain.cpp #include <iostream>#include <vector>#include <string>using namespace std;int main(){ vector<string> msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"}; for (const string& word : msg) { cout << word << " "; } cout << endl;} 配置tasks.jsoncommand + shift + b,vscode会执行tasks.json中的工作。 本文配置的是c++编译,替换tasks.json的内容如下: ...

January 30, 2021 · 1 min · jiezi

关于c#:使用JWT创建安全的ASPNET-Core-Web-API

在本文中,你将学习如何在ASP.NET Core Web API中应用JWT身份验证。我将在编写代码时逐渐简化。咱们将构建两个终结点,一个用于客户登录,另一个用于获取客户订单。这些api将连贯到在本地机器上运行的SQL Server Express数据库。 JWT是什么? JWT或JSON Web Token基本上是格式化令牌的一种形式,令牌示意一种通过编码的数据结构,该数据结构具备紧凑、url平安、平安且自蕴含特点。 JWT身份验证是api和客户端之间进行通信的一种规范形式,因而单方能够确保发送/接管的数据是可信的和可验证的。 JWT应该由服务器收回,并应用加密的平安密钥对其进行数字签名,以便确保任何攻击者都无奈篡改在令牌内发送的无效payload及模仿非法用户。 JWT构造包含三个局部,用点隔开,每个局部都是一个base64 url编码的字符串,JSON格局: Header.Payload.Signature: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIxIiwicm9sZSI6IkFjY291bnQgTWFuYWdlciIsIm5iZiI6MTYwNDAxMDE4NSwiZXhwIjoxNjA0MDExMDg1LCJpYXQiOjE2MDQwMTAxODV9.XJLeLeUIlOZQjYyQ2JT3iZ-AsXtBoQ9eI1tEtOkpyj8Header:示意用于对秘钥进行哈希的算法(例如HMACSHA256) Payload:在客户端和API之间传输的数据或申明 Signature:Header和Payload连贯的哈希 因为JWT标记是用base64编码的,所以能够应用jwt.io简略地钻研它们或通过任何在线base64解码器。 因为这个非凡的起因,你不应该在JWT中保留对于用户的机密信息。 筹备工作: 下载并装置Visual Studio 2019的最新版本(我应用的是Community Edition)。 下载并装置SQL Server Management Studio和SQL Server Express的最新更新。 开始咱们的教程 让咱们在Visual Studio 2019中创立一个新我的项目。我的项目命名为SecuringWebApiUsingJwtAuthentication。咱们须要抉择ASP.NET Core Web API模板,而后按下创立。Visual Studio当初将创立新的ASP.NET Core Web API模板我的项目。让咱们删除WeatherForecastController.cs和WeatherForecast.cs文件,这样咱们就能够开始创立咱们本人的控制器和模型。 筹备数据库 在你的机器上装置SQL Server Express和SQL Management Studio, 当初,从对象资源管理器中,右键单击数据库并抉择new database,给数据库起一个相似CustomersDb的名称。 为了使这个过程更简略、更快,只需运行上面的脚本,它将创立表并将所需的数据插入到CustomersDb中。 USE [CustomersDb]GO/****** Object: Table [dbo].[Customer] Script Date: 11/9/2020 1:56:38 AM ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[Customer]( [Id] [int] IDENTITY(1,1) NOT NULL, [Username] [nvarchar](255) NOT NULL, [Password] [nvarchar](255) NOT NULL, [PasswordSalt] [nvarchar](50) NOT NULL, [FirstName] [nvarchar](255) NOT NULL, [LastName] [nvarchar](255) NOT NULL, [Email] [nvarchar](255) NOT NULL, [TS] [smalldatetime] NOT NULL, [Active] [bit] NOT NULL, [Blocked] [bit] NOT NULL, CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED ( [Id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, _ ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GO/****** Object: Table [dbo].[Order] Script Date: 11/9/2020 1:56:38 AM ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[Order]( [Id] [int] IDENTITY(1,1) NOT NULL, [Status] [nvarchar](50) NOT NULL, [Quantity] [int] NOT NULL, [Total] [decimal](19, 4) NOT NULL, [Currency] [char](3) NOT NULL, [TS] [smalldatetime] NOT NULL, [CustomerId] [int] NOT NULL, CONSTRAINT [PK_Order] PRIMARY KEY CLUSTERED ( [Id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, _ ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GOSET IDENTITY_INSERT [dbo].[Customer] ON GOINSERT [dbo].[Customer] ([Id], [Username], [Password], [PasswordSalt], _ [FirstName], [LastName], [Email], [TS], [Active], [Blocked]) _ VALUES (1, N'coding', N'ezVOZenPoBHuLjOmnRlaI3Q3i/WcGqHDjSB5dxWtJLQ=', _ N'MTIzNDU2Nzg5MTIzNDU2Nw==', N'Coding', N'Sonata', N'coding@codingsonata.com', _ CAST(N'2020-10-30T00:00:00' AS SmallDateTime), 1, 1)GOINSERT [dbo].[Customer] ([Id], [Username], [Password], [PasswordSalt], _ [FirstName], [LastName], [Email], [TS], [Active], [Blocked]) _ VALUES (2, N'test', N'cWYaOOxmtWLC5DoXd3RZMzg/XS7Xi89emB7jtanDyAU=', _ N'OTUxNzUzODUyNDU2OTg3NA==', N'Test', N'Testing', N'testing@codingsonata.com', _ CAST(N'2020-10-30T00:00:00' AS SmallDateTime), 1, 0)GOSET IDENTITY_INSERT [dbo].[Customer] OFFGOSET IDENTITY_INSERT [dbo].[Order] ON GOINSERT [dbo].[Order] ([Id], [Status], [Quantity], [Total], [Currency], [TS], _ [CustomerId]) VALUES (1, N'Processed', 5, CAST(120.0000 AS Decimal(19, 4)), _ N'USD', CAST(N'2020-10-25T00:00:00' AS SmallDateTime), 1)GOINSERT [dbo].[Order] ([Id], [Status], [Quantity], [Total], [Currency], [TS], _ [CustomerId]) VALUES (2, N'Completed', 2, CAST(750.0000 AS Decimal(19, 4)), _ N'USD', CAST(N'2020-10-25T00:00:00' AS SmallDateTime), 1)GOSET IDENTITY_INSERT [dbo].[Order] OFFGOALTER TABLE [dbo].[Order] WITH CHECK ADD CONSTRAINT [FK_Order_Customer] _ FOREIGN KEY([CustomerId])REFERENCES [dbo].[Customer] ([Id])GOALTER TABLE [dbo].[Order] CHECK CONSTRAINT [FK_Order_Customer]GO筹备数据库模型和DbContext创立实体文件夹,而后增加Customer.cs: ...

January 30, 2021 · 8 min · jiezi

关于c:2021年最完整最强解决clion-mingw64中文乱码问题

首先,这篇文章是汇总了网上三种办法,并亲自测试的 测试环境零碎环境:window10 2004clion 2020.3.1编译器:mingw64 办法一——最愚昧的办法办法一是来自搜索引擎最多的解决办法,也是最差劲最没用最不举荐最应该被谩骂的办法参考链接:用Clion运行C++代码时输入中文乱码解决办法本人点进去看就好,没有述说意义 长处:能够解决中文乱码的问题毛病:脱裤子放屁 办法二——另辟蹊径参考链接:解决Windows平台的Clion控制台乱码问题大抵意思就是说把mingw换成cygwin长处:能够解决乱码问题(没有验证过)毛病:因为cygwin在windows下体验并不好,还是改编码格局吧,只是略微麻烦点。 办法三——副作用极大,导致clion无奈失常应用参考链接:Clion 中 的乱码问题正确解决方案(来自官网技术支持)大抵意思就是说,按下Ctrl+Shift+Alt+/,勾销默认选中的run.processes.with.pty 此办法为害人办法 长处:能够解决乱码问题毛病:某些状况下程序间接卡死 办法四——最完满的办法参考链接:Windows下CLion中文乱码最无效的解决形式 最无效的办法:c++在cmakelist.txt增加set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexec-charset=GBK")c语言在cmakelist.txt增加CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fexec-charset=GBK"就完满解决了,此办法临时没有发现副作用

January 29, 2021 · 1 min · jiezi

关于c++:杂谈gccmake和cmake

原创: 杂谈_gcc,make和cmake gcc,make,cmake关系1.gcc是GNU Compiler Collection(就是GNU编译器套件),也能够简略认为是编译器,它能够编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。 2.当你的程序只有一个源文件时,间接就能够用gcc命令编译它。 3.然而当你的程序蕴含很多个源文件时,用gcc命令一一去编译时,你就很容易凌乱而且工作量大 4.所以呈现了make工具make工具能够看成是一个智能的批处理工具,它自身并没有编译和链接的性能,而是用相似于批处理的形式—通过调用makefile文件中用户指定的命令来进行编译和链接的。 5.makefile是什么?简略的说就像一首歌的乐谱,make工具就像指挥家,指挥家依据乐谱指挥整个乐团怎么样演奏,make工具就依据makefile中的命令进行编译和链接的。 6.makefile命令中就蕴含了调用gcc(也能够是别的编译器)去编译某个源文件的命令。 7.makefile在一些简略的工程齐全能够人工手下,然而当工程十分大的时候,手写makefile也是十分麻烦的,如果换了个平台makefile又要从新批改。 8.这时候就呈现了Cmake这个工具,cmake就能够更加简略的生成makefile文件给下面那个make用。当然cmake还有其余性能,就是能够跨平台生成对应平台能用的makefile,你不必再本人去批改了。 9.可是cmake依据什么生成makefile呢?它又要依据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。 10.到最初CMakeLists.txt文件谁写啊?亲,是你本人手写的。 11.当然如果你用IDE,相似VS这些个别它都能帮你弄好了,你只须要按一下那个三角形 12.cmake是make maker,生成各种能够间接管制编译过程的控制器的配置文件,比方makefile、各种IDE的配置文件。 13.make是一个简略的通过文件工夫戳管制主动过程、解决依赖关系的软件,这个主动过程能够是编译一个我的项目。 原文件—cmakelist —cmake —makefile —make —生成可执行文件(make中则蕴含了多条链接以及gcc/g++编译语句)。 简略了解 cmake和autotools正是makefile的下层工具,它们的目标正是为了产生可移植的makefile,并简化本人入手写makefile时的微小工作量。如果你本人入手写过makefile,你会发现,makefile通常依赖于你以后的编译平台,而且编写makefile的工作量比拟大,解决依赖关系时也容易出错。因而,对于大多数我的项目,该当思考应用更自动化一些的 cmake或者autotools来生成makefile,而不是上来就入手编写。 INCLUDE_DIRECTORIES:增加头文件目录 LINK_DIRECTORIES:增加须要链接的库文件目录 LINK_LIBRARIES:增加须要链接的库文件门路,留神这里是全门路 附录GCC 和 cmake的关系?:https://www.zhihu.com/questio... cmake疾速入门:https://blog.csdn.net/kai_zon... cmake 从放弃到入门 - 醍醐灌顶(比拟残缺的案例,强烈推荐):https://blog.csdn.net/iceboy3...cmake中的link_directories, LINK_LIBRARIES, target_link_libraries的区别:https://www.jianshu.com/p/542... Linux下gcc/g++、make和cmake的区别:https://www.cnblogs.com/bokey...

January 28, 2021 · 1 min · jiezi

关于c:C语言中extern详解

在C语言中,修饰符extern用在变量或者函数的申明前,用来阐明“此变量/函数是在别处定义的,要在此处援用”。 extern润饰变量的申明。举例来说,如果文件a.c须要援用b.c中变量int v,就能够在a.c中申明extern int v,而后就能够援用变量v。这里须要留神的是,被援用的变量v的链接属性必须是外链接(external)的,也就是说a.c要援用到v,不只是取决于在a.c中申明extern int v,还取决于变量v自身是可能被援用到的。这波及到c语言的另外一个话题--变量的作用域。可能被其余模块以extern修饰符援用到的变量通常是全局变量。还有很重要的一点是,extern int v能够放在a.c中的任何中央,比方你能够在a.c中的函数fun定义的结尾处申明extern int v,而后就能够援用到变量v了,只不过这样只能在函数fun作用域中援用v罢了,这还是变量作用域的问题。对于这一点来说,很多人应用的时候都心存顾虑。如同extern申明只能用于文件作用域似的。extern润饰函数申明。从实质上来讲,变量和函数没有区别。函数名是指向函数二进制块结尾处的指针。如果文件a.c须要援用b.c中的函数,比方在b.c中原型是int fun(int mu),那么就能够在a.c中申明extern int fun(int mu),而后就能应用fun来做任何事件。就像变量的申明一样,extern int fun(int mu)能够放在a.c中任何中央,而不肯定非要放在a.c的文件作用域的范畴中。对其余模块中函数的援用,最罕用的办法是蕴含这些函数申明的头文件。应用extern和蕴含头文件来援用函数有什么区别呢?extern的援用形式比蕴含头文件要简洁得多!extern的应用办法是直接了当的,想援用哪个函数就用extern申明哪个函数。这大略是KISS准则的一种体现吧!这样做的一个显著的益处是,会减速程序的编译(确切的说是预处理)的过程,节省时间。在大型C程序编译过程中,这种差别是非常明显的。此外,extern修饰符可用于批示C或者C++函数的调用标准。比方在C++中调用C库函数,就须要在C++程序中用extern “C”申明要援用的函数。这是给链接器用的,通知链接器在链接的时候用C函数标准来链接。次要起因是C++和C程序编译实现后在指标代码中命名规定不同。

January 28, 2021 · 1 min · jiezi

关于c++:C中的类型转换下强制类型转换

在上篇与中篇中,咱们探讨了隐式类型转换及其与函数重载之间的相干话题。本篇将要探讨的即为类型转换的另一大分支——强制类型转换。 9. C格调的强制类型转换在C语言中,强制类型转换存在两种等价模式:Type(Value)或(Type)Value。 参考以下代码: int main(){ (int *) malloc(0); // (Type)Value模式的强制类型转换 int(0.); // Type(Value)模式的强制类型转换}上述代码中,咱们别离应用了C语言的提供的两种强制类型转换的等价模式将void 转为了int ,以及将double转为了int。 10. static_cast在C++中,static_cast相当于C语言中的强制类型转换语法。static_cast用于在编译期对某种类型的变量进行强制类型转换。 参考以下代码: int main(){ static_cast<int *>(malloc(0)); static_cast<int>(0.);}上述代码中,咱们应用了static_cast别离将void 转为了int ,以及将double转为了int。 11. const_castconst_cast是C++中专用于解决与const相干的强制类型转换关键字,其性能为:为一个变量从新设定其const形容。即:const_cast能够为一个变量强行减少或删除其const限定。 须要明确的是,即便用户通过const_cast强行去除了const属性,也不代表以后变量从不可变变为了可变。const_cast只是使得用户接管了编译器对于const限定的管理权,故用户必须恪守“不批改变量”的承诺。如果违反此承诺,编译器也不会因而而引发编译时谬误,但可能引发运行时谬误。 上面探讨const_cast的主要用途。 考查以下代码: struct A { A &test() { return *this; } };int main(){ A().test();}这段代码看上去运行失常。但如果: struct A { A &test() { return *this; } };int main(){ const A a; a.test(); // Error!}咱们试图用一个const对象去调用非const成员函数,此时,为了调用此成员函数,const A this就须要转换为A this,这显然是不行的。 通过上述探讨,咱们能够将代码批改为如下: struct A { const A &test() const { return *this; } };int main(){ const A a; a.test();}咱们将this指针申明为const A ,解决了此问题。但不难发现,如果咱们通过一个非const对象调用此办法,其返回值也会被转为const,从而不再能够持续调用任何承受A this的成员函数。这显著不是咱们想要的后果: ...

January 28, 2021 · 2 min · jiezi

关于c++:C中的类型转换中隐式类型转换与函数重载

在上篇中,咱们探讨了C++中与隐式类型转换相干的一些话题,而函数重载是与隐式类型转换相干的又一大重要话题,本篇将要探讨的内容即为隐式类型转换与函数重载之间的相干话题。 6. 隐式类型转换与重载确定C++中,如果同时定义了多个函数名称雷同,但函数签名不同的函数,则此行为称为函数重载。调用重载函数时,编译器将依据调用的参数数量与类型确定被调用的是哪一个函数,此过程称为重载确定。在重载确定过程中,如果编译器发现不止一个函数都是以后调用的最佳版本,则将引发二义性编译时谬误。 须要申明的是:重载确定是一个非常复杂的话题,本文没有对重载确定的所有状况进行详尽的阐述,而只是提出了其中一些与隐式类型转换关联较大的,或具备代表性的话题进行阐述。 首先,援用《C++ Primer》中对于重载确定的隐式类型转换等级的阐明: 为了确定最佳匹配,编译器将实参类型到形参类型的转换划分成几个等级,具体排序如下所示: 准确匹配,包含以下状况:实参类型和形参类型雷同实参从数组类型或函数类型转换成对应的指针类型向实参增加顶层const或从实参中删除顶层const通过const转换实现的匹配通过类型晋升实现的匹配通过算术类型转换或指针转换实现的匹配通过类类型转换实现的匹配依据这段内容,咱们能够失去以下要点: 数组向指针,以及函数向函数指针的隐式类型转换并不被C++视为隐式类型转换,其只是语法上的差异显然,顶层const在不同变量之间不存在传递性波及底层const的类型转换被视为最靠近准确匹配的隐式类型转换类型晋升优先于算术类型转换自定义的类型转换等级最低,且各种自定义类型转换之间无先后差异咱们首先来看一个最简略的例子: void test(int) {}void test(int, int = 0) {}int main(){ test(0); // 调用哪一个test?}上述代码中,咱们仅通过一个int调用了test函数,此时,编译器无奈确定调用的函数版本应该是void test(int)还是void test(int, int = 0),所以此调用是具备二义性的。 再来看一个依据形参类型进行重载确定的例子: void test(int) {}void test(double) {}int main(){ test(0); // void test(int) test(0.); // void test(double) test('0'); // void test(int),因为char -> int比char -> double更优}上述代码中,显然,test(0)调用是void test(int)版本的准确匹配,且test(0.)调用是void test(double)版本的准确匹配。考查test('0'),因为char -> int属于类型晋升,其比char -> double更优,故编译器抉择了void test(int)版本,并将char通过隐式类型转换转为int。 接下来探讨用户自定义的类型转换与重载确定之间的关系。 首先,C++对于隐式类型转换有一条十分重要的规定:对于单次隐式类型转换,用户定义的隐式类型转换计划与算术类型转换各可呈现一次,且程序不限。 围绕此条性质,首先能够失去的论断是:不容许呈现不止一次的用户定义的隐式类型转换。 参考以下代码: // 定义A -> B -> C的隐式类型转换struct A {};struct B { B(const A &) {} };struct C { C(const B &) {} };int main(){ B b = A(); // A -> B C c1 = A(); // Error! 不能够间断应用两次自定义的隐式类型转换 C c2 = B(A()); // B -> C}上述代码中,应用A类对象对B类变量赋值是可行的,因为咱们定义了A -> B的转换构造函数,但如果咱们试图通过多个转换构造函数实现A -> B,而后B -> C的隐式类型转换,则会引发编译时谬误。 ...

January 28, 2021 · 3 min · jiezi

关于c++:C中的类型转换上隐式类型转换

0. 引言不同的数据在计算机内存中的存储形式不同,导致了“类型”这一抽象概念的呈现。对于一个变量而言,其必须要答复三个问题: 在哪能够拜访到这个变量的终点?从终点向后须要读取多少内存?应该如何解析读取到的二进制数据?上述的三个问题中,问题1,由内存地址答复,问题2和3,均由类型答复。由此可见,类型与内存地址独特形成了一个变量的残缺组分。之所以不能对void *取值,也是因为无法回答问题2和3导致。 进一步的,咱们能够失去一条非常重要的论断:对于两个不同类型的变量,因为其对问题2和3的答案不同,故如果将这样的两个变量间接进行运算,在绝大多数状况下都将无奈产生有价值的计算结果。故在简直所有的编程语言中都有一条重要的规定:不同类型的两个变量无奈间接进行运算。 尽管不同类型的两个变量无奈进行运算,但显然,咱们可将其中的一个变量通过类型转换,转为与另一个变量类型统一,此时就满足“同类型变量能力进行运算”这一规定了。同时,因为某些类型转换是“理所应当”的,而另一些不是,故由此又派生出两个概念:隐式类型转换与显式类型转换。隐式类型转换指不通过专门的类型转换操作,而是通过其余规定或代码上下文隐式产生的类型转换,而显式类型转换则通过专门的类型转换操作进行转换,显式类型转换具备强制性,其将不受任何类型转换以外的因素影响,故显式类型转换又称为强制类型转换。 在C++中,类型转换是一个非常复杂的话题。本文将先从隐式类型转换动手,逐渐探讨各类C++的类型转换话题。 1. 类型晋升与算术类型转换算术类型转换专指C++提供的各种内置算术类型之间的隐式类型转换。内置算术类型次要包含以下类型: boolchar, signed char, unsigned charshort, int, long, long long, unsigned short, unsigned int, unsigned long, unsigned long longfloat, double, long doublesize_t, ptrdiff_t, nullptr_t等其余非凡类型算术类型转换是一类不齐全明确的,且与底层密切相关的隐式类型转换。其遵循以下几条次要准则: 对于同类算术类型,如short与int,float与double,占用较小内存的类型将转换成另一类型。如short + int将被转换为int + int。此种类型转换称为类型晋升。整形将转为浮点型。如int + double将被转换为double + double。仅当无符号类型占用的内存小于有符号类型时,无符号类型将产生类型晋升从而转为有符号类型,否则,有符号类型将转为无符号类型。这是一个十分须要留神的点。参考以下代码: int main(){ unsigned short a = 1; unsigned b = 1; cout << (a > -1) << " " << (b > -1) << endl; // 1 0!}上述代码中,-1作为int间接量而存在,因为变量a是unsigned short类型,故其将被转为int,值仍为1。但因为变量b的类型是与int同级的unsigned类型,故此时-1将被转为unsigned类型,这显著不是咱们须要的后果。由此可见,当有符号类型与无符号类型(如size_t)产生混用时,肯定要小心可能会产生的隐式类型转换。 ...

January 28, 2021 · 2 min · jiezi

关于c#:如何创建一个验证请求的API框架

开发一款胜利软件的要害是良好的架构设计。优良的设计不仅容许开发人员轻松地编写新性能,而且还能丝滑的适应各种变动。 好的设计应该关注应用程序的外围,即畛域。 可怜的是,这很容易将畛域与不属于这一层的职责混同。每减少一个性能,就会使了解外围畛域变得更加艰难。同样蹩脚的是,未来就更难重构了。 因而,爱护畛域层不受利用程序逻辑影响是很重要的。其中一个优化是对传入申请的验证。为了避免验证逻辑渗透到畛域级别,咱们心愿在申请达到畛域级别之前验证申请。 在这篇文章中,咱们将学习如何从畛域层中提取验证。在咱们开始之前,本文假如API应用command模式将传入申请转换为命令或查问。本文中所有的代码片段都应用了MediatR。 command模式的益处是将外围逻辑从API层分离出来。大多数实现command模式的库也公开了能够连贯到其中的中间件。这很有用,因为它提供了一个解决方案,能够增加须要与每个命令一起执行的利用程序逻辑。 MediatR申请 应用C# 9中引入的record类型,它能够把申请变成一行代码。另一个益处是,实例是不可变的,这使得所有变得可预测和牢靠。 record AddProductToCartCommand(Guid CartId, string Sku, int Amount) : MediatR.IRequest; 为了散发上述命令,能够将传入的申请映射到控制器中。 [ApiController][Route("[controller]")]public class CustomerCartsController : ControllerBase{ private readonly IMediator _mediator; public CustomerCartsController(IMediator mediator) => _mediator = mediator; [HttpPost("{cartId}")] public async Task<IActionResult> AddProductToCart(Guid cartId, [FromBody] CartProduct cartProduct) { await _mediator.Send(new AddProductToCartCommand(cartId, cartProduct.Sku, cartProduct.Amount)); return Ok(); }}MediatR验证 咱们将应用MediatR管道,而不是在控制器中验证AddProductToCartCommand。 通过应用管道,能够在处理程序解决命令之前或之后执行一些逻辑。在这种状况下,提供一个集中的地位,在命令达到处理程序(畛域)之前在该地位对其进行验证。当命令达到它的处理程序时,咱们不再须要放心命令是否无效。 尽管这看起来是一个微不足道的更改,但它清理了畛域层中每个处理程序。 现实状况下,咱们只心愿在畛域中解决业务逻辑。删除验证逻辑解放了咱们的思维,这样咱们就能够更关注业务逻辑。因为验证逻辑是集中的,它确保所有命令都失去验证,而没有一条命令漏过破绽。 在上面的代码片段中,咱们创立了一个ValidatorPipelineBehavior来验证命令。当命令被发送时,ValidatorPipelineBehavior处理程序在它达到畛域层之前接管命令。ValidatorPipelineBehavior通过调用对应于该类型的验证器来验证该命令是否无效。只有当申请无效时,才容许将申请传递给下一个处理程序。如果没有,则抛出InputValidationException异样。 咱们将看看如何应用FluentValidation在验证中创立验证器。当初,重要的是要晓得,当申请有效时,将返回验证音讯。验证的细节被增加到异样中,稍后将用于创立响应。 public class ValidatorPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>{ private readonly IEnumerable<IValidator<TRequest>> _validators; public ValidatorPipelineBehavior(IEnumerable<IValidator<TRequest>> validators) => _validators = validators; public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { // Invoke the validators var failures = _validators .Select(validator => validator.Validate(request)) .SelectMany(result => result.Errors) .ToArray(); if (failures.Length > 0) { // Map the validation failures and throw an error, // this stops the execution of the request var errors = failures .GroupBy(x => x.PropertyName) .ToDictionary(k => k.Key, v => v.Select(x => x.ErrorMessage).ToArray()); throw new InputValidationException(errors); } // Invoke the next handler // (can be another pipeline behavior or the request handler) return next(); }}应用FluentValidation进行验证 ...

January 28, 2021 · 3 min · jiezi

关于c:C语言Windows编程入门简介

学习C语言很久了,是不是始终在跟黑乎乎的屏幕打交道,像QQ、360、VC6.0这样的软件都是带界面的,怎么做到的呢?后面咱们讲的”黑屏“叫控制台应用程序(Win32 Console Application),也称DOS程序(或MS-DOS程序)。DOS是晚期的命令式操作系统,很难做出丑陋的界面,除了开发人员,”黑屏“对普通用户很不敌对。带界面的程序叫Windows应用程序(Win32 Application)。Windows是一款古代操作系统,带有丰盛的交互界面,应用简略,无需记忆繁冗的命令。应用C语言能够开发出Windows应用程序,也就是带界面的程序,只是绝大部分C语言教程没有讲,它们只讲了根本语法,让很多初学者认为学C语言没用,什么都做不进去。其实不是这样的,C语言只是一种工具,须要与Windows零碎联合,借助Windows提供的函数能力开发出丑陋的程序。Windows API 编程、Windows编程、Windows SDK 编程是一个概念。 什么是windos编程: 在C语言中,应用fopen()函数能够关上一个文件,感觉非常简单。文件保留在硬盘上,要通过简单的解决能力显示,这些细节对咱们来说是通明的,由操作系统实现。也就是说,咱们调用fopen()函数来告诉操作系统,让操作系统关上一个文件。那么,咱们如何通知操作系统关上文件呢?看似简略的操作到底层都非常复杂,关上文件首先要扫描硬盘,找到文件的地位,而后从文件中读取一部分数据,将数据放进I/O缓冲区,放进内存;这些数据都是0、1序列,还要对照ASCII表或Unicode表”翻译“成字符,再在显示器上显示进去。这个过程如果要让程序员来实现,那几乎是噩梦!怎么办呢?Windows想了一个很好的方法,它事后把这些简单的操作写在一个函数外面,编译成动态链接库(DLL),随Windows一起公布,程序员只须要简略地调用这些函数就能够实现简单的工作,让编程变得简略乏味。这些封装好的函数,叫做 API(Application Programming Interface),即应用程序编程接口。API 函数以C语言的模式向外裸露,能够通过C语言间接调用。除了函数,Windows 还事后定义了很多数据类型(应用C语言的 typedef 关键字定义)。狭义上来说,这些数据类型也是 API 的一部分。API 屏蔽了很多细节,大大简化了程序员的工作,这就是操作系统的威力,岂但让普通用户使用方便,也让程序员如释重负。在Windows上运行的程序(包含MS-DOS程序),实质上都是通过调用Windows API来实现性能的,包含QQ、360、VC6.0等,别看这些团队牛,也不可能从底层做起,那几乎不可设想。C语言也一样,也是调用Windows API,fopen() 函数就是通过调用 CreateFile() 函数实现的。CreateFile() 是Windows API中的一个函数,能够用来关上或创立文件。通常所说的 SDK 编程就是间接调用API 函数进行编程。SDK 是 Software Development Kit 的缩写,即软件开发工具包。Windows API 函数成千上万,具体理解每一个函数的用法是不可能的,也是齐全没有必要的。只需晓得哪些性能由哪些API 函数提供就行了,等应用它们时再去查阅帮助文件。带界面的程序的业余称说是GUI程序。GUI 是 Graphical User 域名交易Interface 的简写,即图形用户界面。本教程将教你应用 Windows API 来编写GUI程序,编程语言为C语言。 C语言学来干什么? 你或者学C语言很久了,没什么感觉,可能学python都能够抓取网站的数据了,C语言还是默默无声。 不要放弃,明天咱们介绍了windows编程,windows编程就是使用C语言,咱们的底层零碎C语言的卓越作品。 那些特地牛的软件能够没有C语言吗?请记住:C语言永不过期!

January 26, 2021 · 1 min · jiezi

关于c:有意思的C语言运算符

在C语言中,运算符用于执行程序代码运算,会针对两个或者两个以上操作数进行运算。比方:5 - 2,它的操作数是 5 和 2,而运算符则是 “-”。常见的运算符可大抵分为 4 种类型:算术运算符、关系运算符、赋值运算符和逻辑运算符;它优先级从低到高的程序为: 赋值运算符 < 逻辑运算符 < 关系运算符 < 算术运算符;上面对这4种类型一一解说。 1、赋值运算符 赋值运算符可分为简略赋值、复合算术赋值和复合位运算赋值。 1、1 简略运算符只有一个 “=”,它的用法可用如下例子示意: int n = 2;1、2 复合算术赋值运算符有 5 个,别离为 “+=”, “-=”, “*=”, “/=”, “%=”,它们的用法可用如下例子示意: int j = 1;j += 2; //等同于 j = j + 2,示意j的值加 2 后再赋值给jj -= 2; //等同于 j = j - 2,示意j的值减 2 后再赋值给jj *= 2; //等同于 j = j * 2,示意j的值乘以 2 后再赋值给jj /= 2; //等同于 j = j / 2,示意j的值除以 2 后再赋值给jj %= 2; //等同于 j = j % 2,示意j的值除以 2 后再赋值给j1、3 复合位运算赋值运算符有 5 个,参加运算的量,按二进制位进行运算,别离是 “&=”, “|=”, “^=”, “>>=”, “<<=”,它们的用法可用如下例子示意: ...

January 26, 2021 · 2 min · jiezi

关于c:struct和typedef-struct区别

1.构造体的定义: 容许用户本人建设由不同类型数据组成的组合型的数据结构,它称为构造体(实际上应称为 构造体类型)。 2.上面以一个构造体实例来阐明一下struct的用法: struct os_tcb{ OS_STK    *OSTCBStkPtr; OS_STK    *OSTCBStkBottom; INT32U      OSTCBStkSize; INT16U      OSTCBOpt; INT16U      OSTCBId; };Sturct 是申明构造体类型时所必须应用的关键字,不能省略。os_tcb 是构造体名花括号内 是该构造体所包含的子项,称为构造体成员。后面只是建设了一个构造体类型,它相当于一个模型,并没有定义变量,其中并无具体数据,系统对之也不调配存储单元。为了能在程序中应用构造体类型的数据,该当定义构造体类型的变量,并在其中寄存具体的数据。 能够采取以下3中形式定义构造体类型变量。 (1)先申明构造体类型,再定义该类型的变量定义下面的构造体类型后struct os_tcb    OS_TCB; // 在定义了构造体变量后,零碎会为之分配内存单元(2)在申明类型的同时定义变量struct os_tcb{ OS_STK    *OSTCBStkPtr; OS_STK    *OSTCBStkBottom; INT32U      OSTCBStkSize; INT16U      OSTCBOpt; INT16U      OSTCBId; } OS_TCB;     // OS_TCB 是一个构造体变量(3)不指定类型名而间接定义构造体类型变量struct { OS_STK    *OSTCBStkPtr; OS_STK    *OSTCBStkBottom; INT32U      OSTCBStkSize; INT16U      OSTCBOpt; INT16U      OSTCBId; } OS_TCB;     // OS_TCB 是一个构造体变量指定了一个无构造体名的构造体类型,显然不能再以此构造体类型去定义其余变量。 注:构造体类型与构造体变量是不同的概念,不要混同。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取后运算。在编译时,对类型不调配空间,只对变量调配空间。 3.上面再以此构造体实例来阐明一下typedef struct的用法: (次要参考技术博客:http://dzdesigned80.blog.163....) 阅读程序发现两种用 typedef struct 定义构造体的办法 第一种:typedef struct os_tcb{ OS_STK    *OSTCBStkPtr; OS_STK    *OSTCBStkBottom; INT32U      OSTCBStkSize; INT16U      OSTCBOpt; INT16U      OSTCBId; }OS_TCB;第二种:typedef struct { OS_STK    *OSTCBStkPtr; OS_STK    *OSTCBStkBottom; INT32U      OSTCBStkSize; INT16U      OSTCBOpt; INT16U      OSTCBId; }OS_TCB;能够看出,下面的区别在于 typedef struct 前面一个跟了标识符,另外一个没有跟标识符,这两个有什么区别呢?这里的os_tcb代表什么?OS_TCB的意义又是什么? 要搞清楚下面的问题,要从两方面动手。 第一 typedef的用法是什么? typedef是在根本类型的根底上定义类型的同义字。留神typedef并不产生新的类型。例如 typedef int exam_score;这里的exam_score 就是一种根本类型,它的意义等同于 int,那么即能够用它来定义整型变量,例如:exam_score  LIMING。 ...

January 26, 2021 · 1 min · jiezi

关于c++:CS144-Lab-Assignments-手写TCP-LAB1

CS 144: Introduction to Computer Networking, Fall 2020https://cs144.github.io/My Repohttps://github.com/wine99/cs1... 工作 TCP 接受方接管到乱序且可能重叠的报文段,StreamReassembler 须要将收到的报文段按状况送入 ByteStream (lab0 实现的),或抛弃,或暂存(在适合的时候重组送入 ByteStream)。 留神点: 报文段蕴含索引、长度、内容,lab1 的索引从 0 开始增长,不会溢出绕回。任何报文段,包含新收到的和暂存的,只有能够,就应该立即送入 ByteStream(可能须要手动重组和去重叠)。容量的限度如下图所示。 思路用 set 来暂存报文段,依照报文段的 index 大小比照重载 < 运算符。用 _eof 来保留是否曾经收到过有 EOF 标识的段。收到新段时,通过比照新段的 index、length 和 _first_unacceptable,_first_unassembled 对新段进行必要的剪切,而后解决重叠(调用 _handle_overlap)。解决重叠的逻辑:遍历每个暂存段,如果与新段产生重叠,合并暂存段与新段(调用 _merge_seg,总是往新段上合并,合并后删除重叠的暂存段)。合并段的办法:分类探讨,两个段总共会有四种不同的重叠状况,别离解决。解决完重叠后,调用 _stitch_output:遍历所有暂存段,将可合并的暂存段接入 ByteStream 中。最初,当 _eof 为真且 unassembled_bytes 为 0 时,调用 ByteSteram 的 end_input。代码stream_reassembler.hh: class StreamReassembler { private: // Your code here -- add private members as necessary. ByteStream _output; //!< The reassembled in-order byte stream size_t _capacity; //!< The maximum number of bytes size_t _first_unread = 0; size_t _first_unassembled = 0; size_t _first_unacceptable; bool _eof = false; struct seg { size_t index; size_t length; std::string data; bool operator<(const seg t) const { return index < t.index; } }; std::set<seg> _stored_segs = {}; void _add_new_seg(seg &new_seg, const bool eof); void _handle_overlap(seg &new_seg); void _stitch_output(); void _stitch_one_seg(const seg &new_seg); void _merge_seg(seg &new_seg, const seg &other); public:stream_reassembler.cc: ...

January 25, 2021 · 5 min · jiezi

关于c:C语言-一个简单的C程序-c语言学习计划第2天

一个简略的C程序所蕴含的内容1.头文件艰深的了解来说,相似于将stdio.h的文件中所有的内容复制粘贴到以后文件中 #include <stdio.h> //蕴含另一个文件2.正文//不同的正文格调/* 不同的正文格调 */3.main()函数c程序的根本模块,c程序必定会从main()函数开始执行 int main(void) //一个简略的C程序//int是返回“整数”的数据类型,返回给操作系统//void示意不须要传入函数任何信息4.花括号记录了函数体的开始和完结的地位 //函数开始{5.申明int num; //申明变量num//无效的标识符只能包含小写字母,大写字母,数字和下划线,数字不能作为结尾int num,feet//多条申明6.赋值num = 1;//须要先做申明才可能赋值,等于号为赋值号并不是比照左右是否相等,这里的等于号代表了将左边的数据赋值到右边的变量中。7.输入函数c语言中会有很多的输入函数,printf是最常见的一个,此函数在括号内接管到数据,从而将其输入到屏幕中 printf("I am a simple"); printf("computer.\n"); printf("My favorite number is %d because it is first.\n",num); printf("press Enter to quit the game..."); getchar();8.return函数在程序的最初返回出0 return 0;}//函数完结9.函数申明#include<stdio.h>void secondFunc(void)int main(void){ printf("引入另一个函数,他在这里\n"); secondFunc();}void secondFunc(void){ printf("我在这里,我叫secondFunc");}总结:一个C程序的构造#include <stdio.h> int main(void)//函数头//函数体{ //申明 //语句 return 0;}//大部分语句以分号结尾顺便记录一下g++避免中文呈现乱码的状况间接编译的办法, g++ -fexec-charset=GBK anotherFunc.c -o test

January 25, 2021 · 1 min · jiezi

关于c++:stdasync的使用总结

C++98规范中并没有线程库的存在,直到C++11中才终于提供了多线程的规范库,提供了治理线程、爱护共享数据、线程间同步操作、原子操作等类。多线程库对应的头文件是#include <thread>,类名为std::thread。 然而线程毕竟是比拟贴近零碎的货色,应用起来依然不是很不便,特地是线程同步及获取线程运行后果上就更加麻烦。咱们不能简略的通过thread.join()失去后果,必须定义一个线程共享的变量来传递后果,同时还要思考线程间的互斥问题。好在C++11中提供了一个绝对简略的异步接口std::async,通过这个接口能够简略的创立线程并通过std::future中获取后果。以往都是本人去封装线程实现本人的async,当初有线程的跨平台接口能够应用就极大的不便了C++多线程编程。 先看一下std::async的函数原型 //(C++11 起) (C++17 前)template< class Function, class... Args>std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>> async( Function&& f, Args&&... args );//(C++11 起) (C++17 前)template< class Function, class... Args >std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>> async( std::launch policy, Function&& f, Args&&... args ); 第一个参数是线程的创立策略,有两种策略可供选择: std::launch::async:在调用async就开始创立线程。std::launch::deferred:提早加载形式创立线程。调用async时不创立线程,直到调用了future的get或者wait时才创立线程。默认策略是:std::launch::async | std::launch::deferred也就是两种策略的合集,具体什么意思前面具体再说 第二个参数是线程函数 线程函数可承受function, lambda expression, bind expression, or another function object 第三个参数是线程函数的参数 不再阐明 返回值std::future std::future是一个模板类,它提供了一种拜访异步操作后果的机制。从字面意思上看它示意将来,这个意思就十分贴切,因为她不是立刻获取后果然而能够在某个时候以同步的形式来获取后果。咱们能够通过查问future的状态来获取异步操作的构造。future_status有三种状态: deferred:异步操作还未开始ready:异步操作曾经实现timeout:异步操作超时,次要用于std::future<T>.wait_for()示例: //查问future的状态std::future_status status;do { status = future.wait_for(std::chrono::seconds(1)); if (status == std::future_status::deferred) { std::cout << "deferred" << std::endl; } else if (status == std::future_status::timeout) { std::cout << "timeout" << std::endl; } else if (status == std::future_status::ready) { std::cout << "ready!" << std::endl; }} while (status != std::future_status::ready); std::future获取后果的形式有三种: ...

January 25, 2021 · 2 min · jiezi

关于c++:CS144-Lab-Assignments-手写TCP-LAB0-LAB1

CS 144: Introduction to Computer Networking, Fall 2020https://cs144.github.io/My Repohttps://github.com/wine99/cs1... LAB0 在 master 分支,LAB1 - 7 在对应名字的分支。 webgetWhat is webget?参照 lab0.pdf 2.1 Fetch a Web page, 如下所示。 其成果等同于 Write Webget参考 API 文档 https://cs144.github.io/doc/l...。 留神 lab0.pdf 中的几点提醒: Please note that in HTTP, each line must be ended with “rn” (it’s not sufficient to use just “n” or endl).Don’t forget to include the “Connection: close” line in your client’s request. This tells the server that it shouldn’t wait around for your client to send any more requests after this one. Instead, the server will send one reply and then will immediately end its outgoing bytestream (the one from the server’s socket to your socket). You’ll discover that your incoming byte stream has ended because your socket will reach “EOF” (end of file) when you have read the entire byte stream coming from the server. That’s how your client will know that the server has finished its reply.Make sure to read and print all the output from the server until the socket reaches “EOF” (end of file) — a single call to read is not enough.void get_URL(const string &host, const string &path) { // Your code here. // You will need to connect to the "http" service on // the computer whose name is in the "host" string, // then request the URL path given in the "path" string. // Then you'll need to print out everything the server sends back, // (not just one call to read() -- everything) until you reach // the "eof" (end of file). // cerr << "Function called: get_URL(" << host << ", " << path << ").\n"; // cerr << "Warning: get_URL() has not been implemented yet.\n"; TCPSocket sock1; sock1.connect(Address(host, "http")); sock1.write("GET " + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); while (!sock1.eof()) { cout << sock1.read(); } sock1.close();}An in-memory reliable byte stream留神上面代码中的 buffer_size 为缓冲的内容大小(等于 _stream.size()),capacity 才是缓冲的大小。只有当 input_ended 为真并且 buffer_size 为 0 时,才是 EOF。 ...

January 24, 2021 · 4 min · jiezi

关于c:Linux学习系统数据文件和信息时间和日期函数口令文件

简介:这节咱们将简略介绍一下Linux零碎中一些数据据。(在这里、咱们只简略介绍几个例子) 1:passwd数据文件和组文件。 a:首先咱们在这里介绍passwd数据文件,此数据文件寄存在/etc/passwd文件目录中。该文件中的数据可能有如下各项的内容。 注:因为不同的零碎,该密钥文件中显示的条目可能不一样。在这里我介绍一个非凡的例子:就是咱们如何组织用于登录,这里我列举几种办法。1>:将登录的shell换成/bin/false。2>:将登录的shell换成/bin/nologin。(能够容许该用户应用ftp等服务)3>:应用命令usermod -s /sbin/nologin 。接下来、咱们介绍一些无关密钥文件的一些函数。struct passwd *getpwuid(uid_t uid);struct passwd* getpwnam(const char* name);这两个函数别离依据用户的ID和名字获取无关用户的一些信息,具体应用办法请参考man手册、这里就不一一赘述了。接下来同样,咱们介绍几个函数对于查看整个口令文件。struct passwd* getpwent();void setpwent();void endpwent();第一个函数是用来获取口令文件的下一项,它返回一个填充好的passwd构造的指针,第二个函数将文件地位从新置为文件开始的地位。第三个函数是开释文件所是哟个的资源。2:零碎标识,获取零碎的一些信息。 函数原型:int uname(struct utsname *name);此函数获取零碎的一些信息。在终端上咱们能够应用uname命令获取一些信息。3:接下来、咱们解说工夫相干的函数。 这里次要介绍一下工夫和日期相干的函数。time_t time(time_t *calptr);//返回与工夫和日期,如果参数不为空的环,将工夫和日期保留到参数指向的内存空间中。int gettimeofday(struct timeval* tp, void* tzp);//返回更加准确的工夫,他返回的是程序执行的工夫。同时、咱们在取得这种以秒数无关的工夫、咱们也须要将这种工夫转换成年月日等各种模式的工夫。同时struct tm构造体以年月日时分秒示意工夫,咱们也能够用这个工夫转换成其它的工夫。如下图所示,各种工夫格局的转换。 在这里,咱们将所有的函数原型列出来。

January 24, 2021 · 1 min · jiezi

关于c#:C基础篇Hello-Wrold

前言揭示:为了可能将知识点学得更加透彻、记得更加牢固 我会通过教学解说的形式把常识写下来 因为在过程中会让人从学生变成老师 这个过程会开掘出新的常识和观点 是一个自我思维切换而达成的常识深度开掘和晋升的过程 如果能帮忙到大家那就最好 如果有讲错的中央还请多多指教!我只是一只菜鸡 感激了解! 1、Hello World程序在学习编程语言之前我要揭示大家一下 学习编程语言最禁忌的一点就是 只看不写 看的时候 大脑:嗯太简略了 我会了! 手:不 你不会 ! 等写的时候就发现 都是些什么玩意 所以咱们肯定要动起手来写 废话不多说 咱们关上vistudio studio编译器 也能够不是VS用你们棘手的就行 新建一个控制台利用我的项目 咱们先从一段简略的代码学起 先来看看执行后果 输入了Hello World! using System;namespace ConsoleApp1{ class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.ReadKey(); } }}咱们来看看一个简略的C#程序结构 using System : 援用名称为System的命名空间namespace ConsoleApp1 :申明ConsoleApp1命名空间 申明后咱们就能够通过using来援用class Program :申明一个Program类Main :程序的入口点Console.WriteLine() :将信息输入到屏幕(就是咱们的控制台窗口)咱们只所以在控制台窗口看到Hello World! 就是这句话的作用 咱们能够自行批改看看成果 咱们把要输入的语句改一下Console.WriteLine("我只是一只Unity小菜鸡"); 控制台窗口就能看到输入了一句 我只是一只Unity小菜鸡 Console.ReadKey() :期待用户按下任意键 为了防止程序编译完后一闪而过 能够把这句话删掉看看有什么变动认真点看 咱们能够发现在这段代码中所有的语句和表达式都要以;分号结尾像这条语句 结尾的时候都会带一个;分号 ...

January 24, 2021 · 1 min · jiezi

关于c:C语言-部署开发环境-c语言学习计划第一天

window10用MingW搭建C语言开发环境部署环境:Window10工具:mingw下载地址:https://mingw.osdn.io/ 1.装置MingW下载实现后失去mingw-get-setup.exe文件 双击关上进入装置界面 装置配置 装置实现后进入界面 Basic setup-> 右键抉择 -> 将所有的都勾选为Mark for installation点击左上角的Installation -> 点击apply changes -> 点击apply 2.配置环境变量将mingW的bin文件目录增加到环境变量中命令行验证环境是否胜利,能够尝试上面的命令: gcc --versiong++ --versiongdb --version装置胜利!!!

January 23, 2021 · 1 min · jiezi

关于c#:进击吧Blazor第一章-2Hello-Blazor

作者介绍 陈超超Ant Design Blazor 我的项目贡献者领有十多年从业教训,长期基于.Net技术栈进行架构与开发产品的工作,Ant Design Blazor 我的项目贡献者,现就职于正泰团体 第二次写专栏,结尾还是不晓得说什么,所以……先来段广告????《进击吧!Blazor!》是自己与张善友老师单干的Blazor零根底入门系列视频,此系列能让一个从未接触过Blazor的程序员把握开发Blazor利用的能力。视频地址:https://space.bilibili.com/48...本系列文章是基于《进击吧!Blazor!》直播内容编写,降级.Net5,改良问题,解说更全面。每一个教程的第一个Demo都是Hello,巧了,Blazor的默认模板就是一个现成的Hello Blazor,咱们就从他的默认模板开始。 环境介绍IDE:Visual Studio 16.8 创立我的项目 抉择Blazor利用设置项目名称,这里我取名“BlazorToDo”是因为接下来第一个残缺Demo是一个待办事项小程序。抉择Blazor利用模式,咱们接下来开发次要以Blazor WebAssembly App进行。ASP.NET Core hosted选项用于管制是否生成带有托管Blazor程序的ASP.NET Core服务端程序,咱们勾上。咱们将BlazorToDo.Server设为启动项,而后启动,应该能看到Hello, world!到这里Hello Blazor我的项目创立结束????我的项目构造下图是我的项目构造 BlazorToDo.ClientBlazor我的项目,自身就是一个Asp.Net Core我的项目,如果只做前端,就能够间接拿这个我的项目进行公布和部署。之后咱们的分享就围绕着这个我的项目进行。 Program.cs程序入口,这里与Web我的项目的差别就是Builder应用了WebAssemblyHostBuilder。 public static async Task Main(string[] args){ var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); await builder.Build().RunAsync();}_Imports.razor全局导入配置,在这里应用using引入后,相当于在所有razor文件中都进行了引入。 App.razorBlazor的根组件,通过Program.cs中的builder.RootComponents.Add<App>进行映射。 wwwroot动态文件寄存地位,用处和Aps.net core雷同,外面的index.html文件就是主页 <!--index.html--><body> <div id="app">Loading...</div> <div id="blazor-error-ui"> An unhandled error has occurred. <a href="" class="reload">Reload</a> <a class="dismiss">????</a> </div> <script src="_framework/blazor.webassembly.js"></script></body> Program.cs文件中builder.RootComponents.Add<App>("#app");中的选择器#app必须能在index.html中找到正确的元素,不然程序无奈失常显示。 Pages业务组件寄存地位,Blazor都是由组件组成的,页面就是含有路由配置的组件。组件文件扩展名razor,天然应用的是Razor语法,以Index.razor文件为例,代码如下 @page "/"<h1>Hello, world!</h1>Welcome to your new app.<SurveyPrompt Title="How is Blazor working for you?" />Razor语法的应用办法在后续分享中重点介绍,此处就不开展了。 ...

January 22, 2021 · 1 min · jiezi

关于c:14最长公共前缀LeetCodeC语言

办法一、横向遍历法// 横向遍历法#include <stdio.h>#include <string.h>#include <stdlib.h>int getCommonPrefix(char *prev, char *next) { int len = strlen(prev) < strlen(next) ? strlen(prev) : strlen(next); int k = 0; while (k < len) { if (prev[k] != next[k]) { return k; } k++; } return k;}char *longestCommonPrefix(char **strs, int strsSize) { if (strsSize <= 0) { return ""; } int commonPrefixLen = strlen(strs[0]); char *commonPrefix = (char *)malloc((commonPrefixLen + 1) * sizeof(char)); strncpy(commonPrefix, *strs, commonPrefixLen); // 给字符串结尾加上空字符,否则会数组拜访出错,导致堆溢出 // 这个问题找了良久,最初发现strncpy只是复制字符,并不会主动在字符串结尾增加空字符 *(commonPrefix + commonPrefixLen) = '\0'; for (int i = 1; i < strsSize; i++) { int len = getCommonPrefix(commonPrefix, *(strs + i)); // 将字符串初始化为全空,尔后复制字符不必放心结尾增加空字符的问题 memset(commonPrefix, '\0', commonPrefixLen + 1); if (len <= 0) { return commonPrefix; } strncpy(commonPrefix, *(strs + i), len); } return commonPrefix;}int main(void) { char *strs[] = {"flower", "flow", "flight"}; printf("%s\n", longestCommonPrefix(strs, 3));} ...

January 22, 2021 · 2 min · jiezi

关于c++:TARS-染色日志|收集记录特定日志

作者|Eaton 导语| 记日志能够说是程序猿/媛日常开发中的粗茶淡饭了。在日常业务场景中,常常须要剖析特定用户的日志,个别的日志记录形式很难满足需要,有什么解决办法呢?TARS 框架中蕴含染色日志的性能,可能记录特定用户的日志,优雅地解决这一问题。本文将会介绍染色日志的原理和性能,以及如何在 TARS 中应用染色日志。 目录背景初识染色日志TARS 染色性能概述染色日志初体验 被动关上染色日志被动关上染色日志增加特定逻辑总结背景很多业务场景中,须要对特定用户的行为进行追踪,比方局部用户反馈服务有 BUG,须要排查,但发现只是个例,要独自找出这些用户的日志进行剖析;又或是 APP 上线了一个新的性能,先对一部分用户凋谢进行测试,须要追踪这部分用户的行为等。 依照个别形式,要在曾经记录的日志中检索这部分用户的日志。看起来挺简略,然而在微服务的大背景下,服务间调用关系简单(如下图),日志扩散在各个服务节点上。对于一次调用,须要先获取调用链,再找出具体服务调用的节点,而后从节点上获取日志,这个过程十分繁琐。 另外,日志的记录会耗费程序的性能,占用用户的计算资源。因而在正式环境中,日常业务都会管制日志打印的量,确保日志打印不影响用户服务。而在对特定用户行为进行剖析时,往往须要记录额定的日志,能力满足剖析等需要,间接减少日志的打印显然不太事实。 可见,传统的日志记录形式无奈满足对特定用户行为的日志记录,染色日志就是来解决这一问题的。 初识染色日志什么是染色日志呢?在一个调用链外面,标记出某个特定需要的过程,让整个调用链里的上下文信息始终被传输上来,就像一开始被标记染色一样,这种标记日志的形式,咱们叫它染色日志。 简略来说,就是咱们只想要某几个用户的日志信息,通过染色日志把这几个用户的日志另外打印一份,并收集在同一个中央,这样咱们在一个中央就能查找到这些染色用户的日志。 咱们能够用染色日志定位一些特定的地位,也能够定一些特定的逻辑。比方某微信用户反馈语音发送存在问题,通过对用户ID(微信号)进行染色,后端服务接管到染色用户的申请后,就会将该用户本次调用的处理过程日志打印进去,能够十分不便地获取咱们须要的要害信息。除了打印日志,还能够通过染色执行特定逻辑,比方新上线一个性能,凋谢给一部分用户应用,通过染色,后端服务能够判断用户是否在测试名单中,再执行相应的服务逻辑。 TARS 染色性能概述TARS 框架反对染色日志性能,能够在某服务某接口中对特定用户号码的音讯进行染色,不便地实时观察该用户引起后续所有相干调用音讯流的日志。下图为 TARS 中的染色流程 染色日志关上后,在业务中通过指定染色的 key 值,例如指定 QQ 号为 123456 的用户,后续该用户的申请都会在框架中被主动染色,并通过日志服务(tarslog)集中打印染色日志。 咱们只须要到 tarslog 服务所在的服务器上查看相应的染色日志即可,具体的门路个别为 /usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/该目录下个别蕴含两种日志文件:染色的滚动日志和染色的按天日志,日志文件名格局别离为 tars_dyeing.dyeing_roll_yyyymmdd.log, tars_dyeing.dyeing_day_yyyymmdd.log,比方: # 染色滚动日志tars_dyeing.dyeing_roll_20201103.log# 染色按天日志tars_dyeing.dyeing_day_20201103.log滚动日志是服务的本地日志,个别用于记录服务调试信息;按天日志是服务的近程日志,个别用于记录重要的业务信息。开启染色后,如果接管到染色的申请,两种日志都会额定打印一份到 tarslog,只记录染色申请打印的日志,每天保留一个文件。对于滚动日志和按天日志的用法以及更多信息,能够看到官网文档中日志局部,这里不再赘述。 染色日志初体验TARS 框架的染色日志有被动关上和被动关上两种形式。接下来让咱们通过实例,理解如何通过这两种形式在 TARS 中应用染色日志。本章中应用的实例源码都能够在这里找到。 被动关上染色日志被动关上,指的是在发动申请的客户端的业务代码中,被动关上框架的染色日志开关。具体流程如下: 在客户端程序适当的中央申明染色日志开关 tars::TarsDyeingSwitch 的对象。调用该开关对象的 enableDyeing 办法即可关上染色日志。被调用的服务也会主动关上染色开关,并打印日志到 tarslog。如果该被调服务还要调用其余服务,则主动传递给下个服务。在染色日志开关敞开前,客户端打印的所有日志和被调用的服务打印的日志,都会额定打印一份到日志服务 tarslog。客户端开关对象析构,染色日志敞开,后续的调用和日志打印不再生成染色日志。上面,咱们通过一个实例来理解如何在客户端(主调方)中被动关上染色日志。 实例这里以 C++ 为例,依照方才介绍的流程,开启染色日志并调用 TARS 服务。 在开始之前,咱们须要先筹备一个 TARS 服务,供之后的客户端调用,源码见 TestServer 源码。咱们创立一个服务,利用名为 TestApp,服务名 TestServer,Obj 名为 Test,Test.tars 文件中定义的接口如下 ...

January 22, 2021 · 4 min · jiezi

关于c:c-Task

1、Task的劣势ThreadPool相比Thread来说具备了很多劣势,然而ThreadPool却又存在一些应用上的不不便。比方: ◆ ThreadPool不反对线程的勾销、实现、失败告诉等交互性操作; ◆ ThreadPool不反对线程执行的先后秩序; 以往,如果开发者要实现上述性能,须要实现很多额定的工作,当初,FCL中提供了一个性能更弱小的概念:Task。Task在线程池的根底上进行了优化,并提供了更多的API。在FCL4.0中,如果咱们要编写多线程程序,Task显然曾经优于传统的形式。 以下是一个简略的工作示例: using System;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp1{ class Program { static void Main(string[] args) { Task t = new Task(() => { Console.WriteLine("工作开始工作……"); //模仿工作过程 Thread.Sleep(5000); }); t.Start(); t.ContinueWith((task) => { Console.WriteLine("工作实现,实现时候的状态为:"); Console.WriteLine("IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted); }); Console.ReadKey(); } }}2、Task的用法2.1、创立工作(一)无返回值的形式 形式1: var t1 = new Task(() => TaskMethod("Task 1")); t1.Start(); Task.WaitAll(t1);//期待所有工作完结 注:工作的状态: Start之前为:Created Start之后为:WaitingToRun 形式2: Task.Run(() => TaskMethod("Task 2"));形式3: Task.Factory.StartNew(() => TaskMethod("Task 3")); 间接异步的办法 //或者 var t3=Task.Factory.StartNew(() => TaskMethod("Task 3")); Task.WaitAll(t3);//期待所有工作完结 //工作的状态: Start之前为:Running Start之后为:Runningusing System;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp1{ class Program { static void Main(string[] args) { var t1 = new Task(() => TaskMethod("Task 1")); var t2 = new Task(() => TaskMethod("Task 2")); t2.Start(); t1.Start(); Task.WaitAll(t1, t2); Task.Run(() => TaskMethod("Task 3")); Task.Factory.StartNew(() => TaskMethod("Task 4")); //标记为长时间运行工作,则工作不会应用线程池,而在独自的线程中运行。 Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning); #region 惯例的应用形式 Console.WriteLine("主线程执行业务解决."); //创立工作 Task task = new Task(() => { Console.WriteLine("应用System.Threading.Tasks.Task执行异步操作."); for (int i = 0; i < 10; i++) { Console.WriteLine(i); } }); //启动工作,并安顿到当前任务队列线程中执行工作(System.Threading.Tasks.TaskScheduler) task.Start(); Console.WriteLine("主线程执行其余解决"); task.Wait(); #endregion Thread.Sleep(TimeSpan.FromSeconds(1)); Console.ReadLine(); } static void TaskMethod(string name) { Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); } }}async/await的实现形式: ...

January 21, 2021 · 9 min · jiezi

关于SegmentFault:美化应用的标签式表单这个方法值得Get

点击获取工具>> Tabbed Form (TabForm)提供了许多Web浏览器中的选项卡式UI,与其余选项卡容器不同,Tabbed Form中的选项卡能够嵌入到表单的标题栏中或显示在标题栏的正下方。 您还能够在选项卡旁边显示其余按钮,这些按钮将实现自定义性能。 TIP:您能够应用Form Assistant组件将表单转换为Tabbed Form。 TIP:通过应用DevExpress Project Template Gallery,只需单击即可创立基于Tabbed Form的残缺选项卡UI应用程序。 通过Tabbed Form,您和您的最终用户能够应用"Add ( + )"选项卡来创立有限数量的选项卡。 如果在设计时创立了选项卡,则能够通过将控件增加到相应的内容容器来填充其内容。 如果选项卡是用代码创立的,则能够通过解决专用事件在其中填充内容。 Tabbed Form的次要性能包含: 任意数量的选项卡选项卡能够显示在标题栏的正下方或正下方最终用户能够在运行时应用内置的Add ("+") 按钮增加选项卡选项卡中的图像敞开选项卡中的按钮将选项卡页拖离以后表单来创立独自的表单自定义外观选项卡旁边的自定义按钮

January 20, 2021 · 1 min · jiezi

关于SegmentFault:13-罗马数字转整数leetcodeC语言

思路: 遍历字符串,比拟以后罗马字符与后一个罗马字符对应的十进制数字的大小。如果大于,则将该数字累加到num,如果小于,则求出他们的差值,并将其累加到num。遍历完结,将num返回即可。 第一版、没有应用哈希表,应用数组模仿 #include <stdio.h>#include <stdlib.h>#include <string.h>int getIndex(char *str, char c) { int k = 0; while (str[k] != '\0') { if (str[k] == c) { return k; } k++; } return -1;}int romanToInt(char *str){ int numArr[] = {1000, 500, 100, 50, 10, 5, 1}; char roman[] = {'M', 'D', 'C', 'L', 'X', 'V', 'I'}; int k = 0; int num = 0; while (str[k] != '\0') { int indexCurt = getIndex(roman, str[k]); // 判断下一个字符是否是空字符,避免字符串越界 // 如果是空字符,就将其下标与前一个字符的下标置为一样 int indexNext = str[k + 1] != '\0' ? getIndex(roman, str[k + 1]) : indexCurt; if (numArr[indexCurt] < numArr[indexNext]) { num += numArr[indexNext] - numArr[indexCurt]; k += 2; } else { num += numArr[indexCurt]; k++; } } return num;}int main(void) { char *str = "MCMXCIV"; printf("%d\n", romanToInt(str));} ...

January 20, 2021 · 1 min · jiezi

关于c#:springcloud-使用初谈二网关

这里说的是zuul 服务过滤 自定义过滤器的实现,须要继承ZuulFilter,须要重写实现上面四个办法: 四个具备4个基本特征:过滤类型、执行程序、执行条件、具体操作filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:pre:能够在申请被路由之前调用routing:在路由申请时候被调用post:在routing和error过滤器之后被调用error:解决申请时产生谬误时被调用filterOrder:通过int值来定义过滤器的执行程序shouldFilter:返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。在上例中,咱们间接返回true,所以该过滤器总是失效。run:过滤器的具体逻辑。须要留神,这里咱们通过ctx.setSendZuulResponse(false)令zuul过滤该申请,不对其进行路由,而后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,当然咱们也能够进一步优化咱们的返回,比方,通过ctx.setResponseBody(body)对返回body内容进行编辑等。 最初,总结一下为什么服务网关是微服务架构的重要局部,是咱们必须要去做的起因:不仅仅实现了路由性能来屏蔽诸多服务细节,更实现了服务级别、平衡负载的路由。实现了接口权限校验与微服务业务逻辑的解耦。通过服务网关中的过滤器,在各生命周期中去校验申请的内容,将本来在对外服务层做的校验前移,保障了微服务的无状态性,同时升高了微服务的测试难度,让服务自身更集中关注业务逻辑的解决。实现了断路器,不会因为具体微服务的故障而导致服务网关的阻塞,仍然能够对外服务。 Zuul 和 nginx的性能比照 论断:Zuul的原始性能十分靠近于Nginx。事实上,在启动预热之后,我的测试后果甚至略好一些(重申免责申明-这并非一个庄重的基准性能测试)。Nginx显示出更多的可预测性能(变动较小),可悲的是在Zuul预热期间,咱们经验了一些小故障(150000个申请中的2个,然而您的微服务应该是容错机制的,对吧?)。 Zuul解决Cookie和重定向 本文来源于:程序员ken,专属平台有csdn、思否(SegmentFault)、 简书、 开源中国(oschina)、掘金,转载请注明出处。

January 19, 2021 · 1 min · jiezi

关于c:Linux学习bash的配置终端颜色显示

1:bash是咱们在登录零碎是执行的shell程序,咱们适当配置属于本人的bash能够不便咱们和Linux零碎的交互。是我本人更改的bash配置。 通常的状况下、在咱们的零碎会保留备份bash配置,在/etc/skel/.bashrc这个地位。我便借助这个地位保留的备份更改了本人的终端色彩显示。如下图所示,是我很喜爱的显示。如果各位须要本人的显示内容,齐全能够本人配置属于本人的bash。上面我将我的配置文件粘贴到这里。 在这里我重点说一下终端色彩显示要批改linux终端命令行色彩,咱们须要用到PS1,PS1是Linux终端用户的一个环境变量,用来阐明命令行提示符的设置。在终端输出命令:#set,即可在输入中找到对于PS1的定义如下: PS1的定义中个罕用的参数的含意如下: \d :#代表日期,格局为weekday month date,例如:"Mon Aug 1" \H :#残缺的主机名称 \h :#仅取主机的第一个名字 \t :#显示工夫为24小时格局,如:HH:MM:SS \T :#显示工夫为12小时格局 \A :#显示工夫为24小时格局:HH:MM \u :#以后用户的账号名称 \v :#BASH的版本信息 \w :#残缺的工作目录名称 \W :#利用basename获得工作目录名称,所以只会列出最初一个目录 \# :#下达的第几个命令 \$ :#提醒字符,如果是root时,提示符为:# ,普通用户则为:$ 由此,咱们可知linux默认的命令行提示信息为:[以后用户的账号名称@主机的第一个名字 工作目录的最初一项]# 2.色彩的设置 F B 30 40 彩色 31 41 红色 32 42 绿色 33 43 黄色 34 44 蓝色 35 45 紫红色 36 46 青蓝色 37 47 红色 依据色彩表,套用入字符色彩设置格局中,就能够对linux终端命令行色彩进行个性化设置了。 3.批改.bashrc文件 通过下面的设置只能扭转以后终端的命令行格局,敞开这个终端,在从新关上的一个终端中命令行格局又会复原到默认的模式。想要永久性的扭转终端命令行格局,须要批改.bashrc文件。 在.bashrc文件中对PS1的内容进行更改就能够做到终端显示了 PS1='${debian_chroot:+($debian_chroot)}\[\033[36;40m\]\u \[\033[1;31;40m\]\W \[\033[1;35;40m\]\$ > \[\033[1;0;0m\]:这是我的配置,心愿你可能喜爱。 同时,这个文件默认在~/.bashrc,关上进行复制粘贴就能够。最初将一张残缺的终端图像贴到这里。心愿你可能喜爱我这份bash配置。 ...

January 18, 2021 · 3 min · jiezi

关于c#:反射

元数据元数据是用一系列表来存储的,生成一个程序集或模块时,编译器会创立一个类型定义表、一个字段定义表、一个办法定义表以及其它表。 反射程序运行的时候解析这些元数据表以获取信息,该行为便是反射。反射容许在运行时发现并应用编译时还不理解的类型及其成员。 反射的性能反射会造成编译时无奈保障类型安全性。反射须要重度依赖字符串,所以会丢失编译时的类型平安。例如执行Type.GetType("A"),在一个程序集中查找类型名为“A”的类型,但程序集理论蕴含的类型可能是“AA”,代码会通过编译,但运行时会出错。反射速度慢,应用反射时,类型及其成员的名称在编译时未知,要应用字符串名称标识每个类型及其成员,以便在运行时发现它们。也就是说在扫描程序集的元数据时,反射要一直的执行字符串的搜寻,而字符串的搜寻执行的是不辨别大小写的比拟,这会进一步影响速度。反射调用一个成员时也会对性能产生影响反射调用办法时,首先必须将实参打包成一个数组,在外部反射必须将这些实参解包到线程栈上。此外在调用办法前,CLR必须查看实参具备正确的数据类型,最初CLR还需确保调用者有正确的平安权限来拜访被调用的成员。 *综上所述,最好防止应用反射技术来拜访字段或者调用办法。 获取Type对象的几种形式Type的静态方法GetType:接管一个string参数,必须指定类型的全名(包含命名空间),如果调用程序集没有定义指定的类型,就查找MSCorLib.dll定义的类型,如果还是没找到就返回nullType的静态方法ReflectionOnlyGetType:行为与GetType类似,只是类型会加载到一个“仅反射”上下文中,不能执行构造类型的实例Activator的静态方法CreateInstance:调用该办法能够传递一个Type对象援用,也能够传递标识了想要创立的类型的一个String。其中间接获取一个类型对象的几个重载版本绝对简略,为类型的结构器传递一组实参,办法返回的是对新对象的一个援用。而应用字符串来指定所需类型的几个重载版本要略微简单一些,首先必须指定另一个字符串来标识定义了类型的那个程序集。其次这些版本返回的不是对新对象的援用,而是一个System.Runtime.Remoting.ObjectHandle对象。ObjectHandle类型容许将一个AppDomain中创立的对象传至其它AppDomain,期间不强制对象具体化,要具体化该对象能够调用ObjectHandle对象的Unwrap办法。在一个AppDomain中调用这个办法时,它会将定义了要具体化的类型的程序集加载到这个AppDomain中。如果对象按援用封送就创立代理类型和对象。如果按值封送,对象的正本会被反序列化。Activator的静态方法CreateInstanceFrom:行为与CreateInstance办法类似,不同的是必须通过字符串来指定类型及其程序集。程序集要应用Assembly的LoadFrom(而非Load)办法加载到调用的AppDomain中。因为没有接管Type参数的版本,所以返回的都是ObjectHandle对象的援用,必须调用ObjectHandle的Unwrap办法进行具体化结构泛型类型的实例static void Main(){ //获取泛型类型的类型对象的一个援用 Type temp = typeof(List<>); //应用int类型关闭泛型类型 Type closedType = temp.MakeGenericType(typeof(int)); //结构关闭类型的实例 object o = Activator.CreateInstance(closedType); Console.WriteLine(o.GetType());}运行后果 发现类型成员字段、结构器、办法、属性、事件和嵌套类型都能够被定义为类型的成员。FCL蕴含一个System.Reflection.MemberInfo的类型,封装了一组所有类型都通用的属性。层次结构图如下: 查问一个类型的成员并显示与之相干的一些信息static void Main(){ Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); //遍历AppDomain中加载的所有程序集 foreach (var item in assemblies) { Console.WriteLine("Assembly: {0}", item); //查找程序集中的类型 foreach (var t in item.GetExportedTypes()) { Console.WriteLine("Type: {0}", t); //发现类型成员 const BindingFlags bf = BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; foreach (var mi in t.GetMembers(bf)) { var typeName = string.Empty; if (mi is Type) typeName = "Type"; else if (mi is FieldInfo) typeName = "FieldInfo"; else if (mi is MethodInfo) typeName = "MethodInfo"; else if (mi is ConstructorInfo) typeName = "ConstructorInfo"; else if (mi is PropertyInfo) typeName = "PropertyInfo"; else if (mi is EventInfo) typeName = "EventInfo"; Console.WriteLine("mi typeName: {0}", typeName); } } }}BindingFlags枚举(筛选返回的成员类型)Default:指定未定义任何绑定标记IgnoreCase:返回与指定字符串匹配的成员(疏忽大小写)DeclaredOnly:只返回被反射的那个类型的成员,疏忽继承的成员Instance:返回实例成员Static:返回动态成员Public:返回公共成员NonPublic:返回非公共成员FlattenHierarchy:返回基类型定义的公共成员和受爱护动态成员遍历反射对象模型图 ...

January 18, 2021 · 3 min · jiezi

关于c:11-盛最多水的容器LeetCode-C语言

双指针法:int maxArea(int* height, int heightSize){ int max = 0; for (int i = 0, j = heightSize - 1; i < j; ) { int min = height[i] <= height[j] ? i : j; if (height[min] * (j - i) > max) { max = height[min] * (j - i); } if (min == i) { i++; } else if (min == j) { j--; } } return max;}

January 18, 2021 · 1 min · jiezi

关于c:flutter使用C代码库android篇

1) 和原生Android开发的NDK技术一样,编译出.so动静库(下文称之为libgalaxy.so,蕴含简略的native_add函数int32_t native_add(int32_t x, int32_t y) {return x + y;})。并把动静库拷贝到flutter我的项目的android/app/src/main/jniLibs子目录下: 要留神因为flutter应用的是比拟新的android技术,所以NDK编译套件也是须要比拟新的,因为libflutter.so提供的平台版本都是比拟新的,如果NDK编译进去的libgalaxy.so动静库只蕴含较老的平台版本,会导致libflutter.so反对的平台libgalaxy.so不反对,导致运行时找不到定义的C函数。 2) 编辑android/app目录下的build.gradle,减少以下内容: release版本要管制包的大小,所以,限定只须要提供armeabi-v7a和arm64-v8a,如果不做此限定,打包时,会把libgalaxy.so的x86和x86_64也打进release版本!这就没有必要了。当前甚至能够只打包arm64-v8a版本。(如果上一步jniLibs目录下只提供了arm64-v8a版本,这一个就不必做了) debug局部,我认为就没有必要做abiFilters限定了,由flutter编译器本人决定吧,多打几个版本进去也无所谓了。 3) main.dart里的内容: main函数下面的局部,能够独自拎进去放在一个dart文件中。 这样就OK了。

January 18, 2021 · 1 min · jiezi

关于c#:浅谈Winform程序的界面布局设计

点击获取工具>>从事Winform开发很多年了,因为我的项目的须要,设计过各种各样的界面成果。一般来说,使用传统的界面控件元素,正当设计布局,可能设计出比拟中规中矩的规范界面;利用一些换肤的控件或者局部界面组件,可能设计出绝对难看一些的界面成果,如以前很流行的ActiveSkin、IrisSkin和DotNetSkin等,这些可能对传统的界面元素进行换肤,的确比规范灰色的界面控件难看了很多。不过随着界面控件的组件倒退,目前个别偏向于是用较为大型的控件组,他们除了提供设计得体的界面控件外,还提供了十分多种绚丽多彩的界面款式供选择,如DotNetBar、netadvantage、DevExpress等大型界面控件组。 无论界面设计如何变动,个别根本准则都是为客户提供直观、易用、体验成果较好的界面成果哦,从Office的倒退历程咱们也能够看到整体的界面成果趋势,从开始的规范控件到目前的Ribbon窗体,从单色调变动到绚丽多彩的界面款式,都给咱们提供很好的界面设计参考,大型的界面组件也是模拟这一趋势。言归正传,咱们来谈谈具体一点的货色,目前我趋向于采纳一种基于Ribbon款式的界面,以及一种基于传统界面联合OutLook款式的界面设计。 一、基于Ribbon款式的界面 以上的界面款式,是一种比拟大气、合乎Office界面成果的界面布局,通过把不同的功能块集中在不同的面板上显示,的确简洁、好看很多,本文不反复介绍该界面成果的优劣,咱们次要来集中看看上面的另外一种界面成果。 二、基于OutLook款式的界面设计其实OutLook款式很早就有,也能够在很多公开的控件组中看到,如果仅仅是谋求局部的OutLook界面成果,而不是整体性的计划,那么CodeProject上的这款开源Outlook组件,预计是其中的佼佼者(http://www.codeproject.com/Articles/43181/A-Serious-Outlook-Style-Navigation-Pane-Control)。不过因为需要的是整体性成果,而且还要思考更多控件界面款式的一致性及好看性,因而咱们还是基于DevExpress界面组来设计这样的OutLook界面成果,会显得更加美观大方一点。界面成果如下所示。 以上通过把一个零碎很多相干的功能模块放到一颗树上进行分类展现,对于一个比较复杂的人力资源管理系统或者其余简单性能的零碎,也是一个比拟正当的布局形式,另外OutLook工具条还是能够暗藏起来,节俭左边多文档界面的数据展现空间,这样整体还是比拟正当及好看的。其中左边的布局,还能够通过SplitContainer形式把它分成多个模块,而后客户想哪个数据显示面板大一点,拖动一下就能够了,这样不至于数据比拟多的时候,导致显示布局不好的状况。上面咱们来介绍下如何实现以上的界面布局成果。 创立一个基于DevExpress.XtraEditors.XtraForm基类的窗体。如下代码所示:`public partial class MainForm : DevExpress.XtraEditors.XtraForm{public MainForm(){InitializeComponent();}}` 在界面设计中,在DevExpress工具箱Navigation & Layout外面拖动增加一个BarManager控件到窗体中,并删除默认的工具栏Tools,并增加一些菜单项和状态条数据。如下所示。 增加PanelControl和NavBarControl,增加一些测试性能按钮。因为咱们须要应用MDI多文档界面成果,因而先设置Mainform的IsMdiContainer属性为True。 而后增加一个PanelControl,设置其Dock为Top布局,为该控件ContentImage设置一个背景图片(当时用PS设计好,保留为png格局即可),增加几个小Lable,设置其的图片和文字。 最初拖入一个NavBarControl控件到界面中,设置其Dock为Left布局,通过控件的右键菜单上的“Run Designer"进入设计界面,先轻易增加一些NavBarGroup和NavBarItem我的项目,粗略设置失去界面成果如下所示。 留神,在NavBarcontrol外面,默认是没有一个Panel能够增加一些非凡的控件,如树、按钮等,默认只有BarItem对象能够增加进入。为了在一个NavBarGroup外面增加这样的控件,须要批改NavBarGroup的属性才行,如下所示。 增加DockManager和XtraTabbedMdiManager 控件实现多文档布局,其最终将以Tab形式进行展示。持续在下面的窗体中增加DockManager控件和XTraTabbedMdiManager控件,这两个控件能够实现在左边以Tab形式展示多文档布局,这样对用户操作来说,能够一次性关上多个窗体进行操作,不便很多,也必将好看,是一种常见的布局展示。为了在窗体激活的时候,在顶部显示敞开按钮,其余的不显示,那么须要设置XTraTabbedMdiManager控件的ClosePageButtonShowMode=InActiveTabPageHeader即可实现了。最终Tab成果如下所示。 以上就是我设计的一个零碎界面的具体操作流程,其实很多时候,介绍总是很快,摸索总是很慢,这个就是常识积攒的效率晋升。当然,要设计好一个零碎界面,除了思考界面的布局好看性、还要思考图标的协调性、还有就是整体的框架,要能够比拟好的适应这些布局控件的操作,不能太过臃肿或者难以浏览。 本文转载自博客园-伍华聪[](https://home.cnblogs.com/u/wu...

January 18, 2021 · 1 min · jiezi

关于c#:NET-5网络操作的改进

随着.net 5在11月的公布,当初是议论网络栈中许多改良的好时机。这包含对HTTP、套接字、与网络相干的安全性和其余网络通信的改良。在这篇文章中,我将重点介绍一些版本中更有影响力和更乏味的变动。 HTTP更好的错误处理  自从.net 3.1公布以来,HTTP畛域进行了许多改良和修复。当应用HttpClien时,最受关注的是增加如何辨别超时和勾销。最后,不得不应用自定义的CancellationToken辨别超时和勾销: class Program{ private static readonly HttpClient _client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) }; static async Task Main() { var cts = new CancellationTokenSource(); try { // Pass in the token. using var response = await _client.GetAsync("http://localhost:5001/sleepFor?seconds=100", cts.Token); } // If the token has been canceled, it is not a timeout. catch (TaskCanceledException ex) when (cts.IsCancellationRequested) { // Handle cancellation. Console.WriteLine("Canceled: " + ex.Message); } catch (TaskCanceledException ex) { // Handle timeout. Console.WriteLine("Timed out: "+ ex.Message); } }}这样做,客户端依然抛出TaskCanceledException(为了兼容),但外部异样是超时时的TimeoutException: ...

January 18, 2021 · 11 min · jiezi

关于c:栈的解读

前沿栈广泛应用在各种软件系统中,所以这块的知识点咱们也要好好把握起来。 定义栈(stack)是限定仅在表尾进行插入或删除操作的线性表。 简略的来说就是一种能够实现"先进后出" 的存储构造 栈相似于箱子 分类栈个别分为两类 动态栈 (相似于用数组实现)动静栈 (相似于用链表实现)算法这边咱们来看看 栈的出栈 和入栈的伪算法 先来看看入栈 //伪代码void push(struct Stack *pS, int val){ struct Node * pNew = (struct Node *)malloc(sizeof(struct Node)); pNew->data = val; pNew->pNext = pS->pTop; pS->pTop = pNew; return;}首先初始化的时候 pTop 和 pBottom 都指向空而后咱们创立一个节点 pNew, 让他指向下一个节点的指针域。这里咱们要留神,这里应该指向的是 pTop所指向的指针域最初把 pNew 赋值给 pTop, 实现pTop 指向新的节点。再来看看出栈 写法 //伪代码bool pop(struct Stack *pS, int * pVal){ struct Node * q = pS->pTop; *pVal = q->data; pS->pTop = q->pNext; free(q); q = NULL; return true; }出栈算法看过来时简略的,但有点要特地留神,就是要记得开释内存,防止野指针所以咱们定义一个 指针变量 q 来做长期存储应用。最初咱们在free()开释内存致谢感激你看完这篇文章,有什么不对的中央欢送指出,谢谢???? ...

January 17, 2021 · 1 min · jiezi

关于c:Linux学习文件IO不带缓冲区原子操作概念

在后面的文章咱们介绍过不带缓冲区的IO,这节咱们次要介绍不带缓冲区的IO相干内容。原子操作对于文件共享是非常重要的,因而咱们将介绍一些原子操作相干概念。 1:文件描述符 对于内核而言,所有关上的文件都通过文件描述符援用。当咱们关上或者创立一个文件的时候,都会返回一个非负的整数,咱们关上和创立文件都用这个非负的整数。同时,通常在咱们执行一个过程的时候,都会默认关上三个文件描述符,他们别离是规范输出(0:STDIN_FILENO)、输入(1:STDOUT_FILENO)、谬误(2:STDERR_FILENO)相关联的。他们的宏定义在unistd.h文件中。文件描述符下限是OPEN_MAX。2:open函数介绍 函数原型:int open(const char* pathname, int flag); int open(const char* pathname, int flag, mode_t mode);pathname:是关上文件的路径名。flag:是关上文件的一些选项。mode:只有咱们须要创立文件的时候,才会将指定mode的模式。O_RDONLY:只以读的形式关上文件。O_WRONLY:只一写的形式关上文件。O_EXCL:测试文件受否存在,如果不存在则创立文件。(注:如果同时指定O_CREAT并且文件曾经存在则出错)O_APPEND:每次写入都追加到文件开端。O_CREAT:如果文件不存在,则创立文件。应用这个选项的时候,须要第三个参数。 mode:权限位,也就是咱们应用ls -l显示的各种读写和执行权限的位。 S_IRWXU:用户有读写执行权限。 S_IRUSR:用户有读权限。 S_IWUSR:用户有写权限。 S_IXUSR:用户有执行权限。 S_IRWXG:同组用户有读写执行权限。 S_IRGRP:同组用户有读权限。 S_IWGRP:同组用户有写权限。 S_IXGRP:同组用户有执行权限。 S_IRWXO:其余用户有读写执行权限。 S_IROTH:其余用户有读权限。 S_IWOTH:其余用户有写权限。 S_IXOTH:其余用户有执行权限。O_TRUNC:如果文件存在的话,并且咱们只为读写关上文件的话,那么文件长度将会截断为0。也就是文件长度会变为0,相当于咱们将文件内容全副删去再从新写入。O_NOBLOCK:指定文件为非阻塞IO,失常状况下在咱们写入文件的时候,咱们都期待写入实现之后再返回。如果指定此flag,那么将间接返回,而不论是否写入实现。O_SYNC:每一次写操作实现之前都会更新文件的属性。O_RSYNC:期待任何对文件同一部分未决写操作实现。(这个标记和上面一个标记不是很了解,如果了解的话,请在评论区探讨。最好是能有一个理论的例子)。O_DSYNC:每次写期待物理操作实现。仅当文件属性根棍以反映文件数据变动时,此标记才会影响文件属性。open函数返回的文件描述符肯定是以后可用的最小文件描述符。文件名和路径名的截断:这个概念我简略介绍一下,就是咱们输出关上文件的路径名的时候,因为咱们输出的太长了,咱们无奈辨认那么长的路径名,就会保留其中的一部分。这样就无奈辨认出具体的关上的文件了(咱们保留这部分路径名可能与其余文件的路径名重名)。咱们这里能够应用pathconf获取一些路径名长度,我发现我的机器长度限度是4096。creat:创立文件函数原型:create(const char *pahtname, mode_t mode);此函数和open函数是有雷同的局部,不做理解。close:敞开关上的文件描述符(就是咱们关上一个文件肯定会用到一些资源去治理这个关上的文件,那么这里敞开就是开释这些被栈用的资源)函数原型:int close(int filedes);lseek函数:更改以后文件的偏移量,也就是咱们从文件哪里开始读写文件。 当咱们关上一个文件或者创立一个新的文件,文件偏移量默认为0。也就是说从文件开始地位读写文件。同时咱们也能够用lseek函数将以后文件偏移量定位到文件指定的置为。 函数原型:lseek(int filedes, off_t offset, int whence); lseek_64(int filedes, off64_t offset, int whence); filedes:是文件描述符。 offset:是偏移的大小。(能够为正<减少文件偏移>,也能够为负<缩小文件偏移>) 对于off_t是否够用的问题,我在这里简略解说一下。 然而咱们看函数原型的时候,有32位和64位两种文件偏移量。如果是32位那么文件偏移量最大时2的32次方减一,64位也是如此。 32位的文件偏移量最大时2TB(2^31-1字节),64位文件最大偏移量2^33TB,应该足够应用了。如果是不同的平台会用不同的大小,这里只列举了32位和64位。具体实现还是靠硬件, 这里就不逐个列举了。 whence:是指定地位开始进行便宜。 SEEK_SET:即从文件结尾为只进行便宜。 SEEK_CUR:从以后文件地位进行便宜。 SEEK_END:从文件开端地位开始便宜。同时lseek也能够测试文件是否设置偏移量,如果文件描述符援用的是一个管道、套接字,则lseek返回-1.read函数:从文件中读取指定字节数目标数据。函数原型:ssize_t read(int filedes, void *buf, size_t nbytes);filedes:文件描述符。buf:读取到字节寄存的缓冲区。nbytes:读取多少个字节。返回值:理论读取到的字节数。理论读取到字节数可能小于咱们要求读取的字节数。(eg,以后文件地位到文件开端还有三十个可读的字节,然而咱们要求读取200个字节,这就返回30个字节。然而在下次读取的时候,返回30个字节。还有从网络中读取数据,有些时候可能因为网络提早读取小于咱们读取到的字节数)。write函数:向文件中写入指定字节数的数据。函数原型:ssize_t write(int filedes, const void* buf, size_t nbytes);同上,buf是写入字节存储地位。nbytes是写入的字节数。返回值是理论写入的字节数。同时,如果咱们指定了O_APPEND,每次咱们写入之前都将文件偏移量设置为文件开端的地位。文件共享:在介绍文件共享之前,咱们先介绍一下内核是应用什么构造示意关上的文件的。内核应用三种数据结构示意关上的文件。(1)每个过程都有一个记录项,记录项抱哈一张关上的文件描述符表,每个文件描述符占用一项。咱们在过程中应用一个整型记录这个文件项的地位。 每个文件描述符相关联的有两局部:文件标记,指向文件表的指针。(2)对于关上的文件内核维持一张文件表。 文件表中有文件状态标记、以后文件的偏移量和v节点指针。(3)每个关上的文件都有一个v节点。 v点蕴含了文件类型和对该文件各种操作的函数指针。同时还有i节点信息,以后文件的长度。对于这些内容理解即可。如下图所示,能够很好的了解这三者之间的关系。 ...

January 17, 2021 · 1 min · jiezi

关于c:Linux学习unix的标准化的实现Linux中各种限制数据类型各种标准化头文件介绍

作为Linux的前身,unix标准化是非常重要的。我在这里挑几个重要的点阐明。 1:Linux中各种限度。 Linux中限度有编译时限度和运行时限度,另外有一些限度是因为咱们的实现不同而不同,因而咱们须要调用对应的函数获取对应的值不同。(eg:编译时限度:整形最大值是什么。运行时限度:文件名能够有多少个字符)对应的咱们能够调用对应的内容获取其限度值: (1)编译时限度 --->头文件。 (2)不是与文件或目录相干的运行时限度--->sysconf函数 (3)与文件或目录相干的运行时限度---->pathconf或fpathconf 在ISO C中定义的限度都是编译时限度,在Linux limits.h文件中定义了C规范限度。在float.h中定义了对于浮点数的各种限度。如下图时ISO C在limint.h头文件中的各种限度值。 POSIX定义了许多零碎实现的限度,这些限度被分成了5类。 (1)不变的最小值,下图中的19个常量。 (2)不变值:SSIZE_MAX。 (3)运行时能够减少的值: (4)运行时不变的值。 (5)路径名可变值。 等等,这些我就不做过多介绍了,因为介绍这么多恐怕咱们也记不住。在日后shi理论应用过程中逐个介绍。 实例:上面获取两个限度的值,#include <unistd.h>#include <limit.h>#include <stdio.h>int main(){ printf("%lu\n", sysconf(_SC_LINE_MAX)); printf("%lu\n", pathconf(".", _PC_LINK_MAX));}来个小总结:对于限度获取这块,咱们就讲这么多。咱们次要是应用这些限度的值,获取办法有两种,头文件、库函数。2:这部分咱们次要将定义的各种数据类型,次要介绍根本的数据类型。如下图所示这些数据类型是我在一本书上截取下来的,日后如果应用到这种数据类型的时候会逐个的具体介绍。 还有一些其余的数据类型:int double long float char short 等,这里就不在这里逐个介绍了。3:我介绍一下ISO C的各种头文件,至于其余头文件就不逐个列出了。 assert.h:验证程序某些判断是否正确。如下是一个试验。输入后果 limit.h各种限度。time.h获取工夫的各种函数。string.h:字符串操作函数集。stdlib.h:实用程序函数。signal.h:信号相干内容。wchar.h:宽字符相干的内容。至于其余的我就间接列出即可,作为理解 本文由博客群发一文多发等经营工具平台 OpenWrite 公布

January 16, 2021 · 1 min · jiezi

关于c#:C常用工具类如何优雅的使用多线程以及优雅的跨线程的解决方案解决线程间操作无效-从不是创建控件的线程访问它

当你须要通过一个耗时操作获取到数据,并扭转窗体或控件的显示时,该工具能够为你解决窗体假死,以及跨线程的问题。 解决System.InvalidOperationException:“线程间操作有效: 从不是创立控件“”的线程拜访它。” 首先看看在我的我的项目中理论应用://多线程工具this.TaskRun(cross =>{ //多线程代码,申请API List<EmpType> types = ApiRoutes.EmpApi.GetTypeList(out string msg); //跨线程代码块 cross.Invoke(delegate { uiDataGridView1.DataSource = types; uiDataGridView1.Refresh(); });});你只须要创立如下工具类:public static class TaskEx{ /// <summary> /// 启动多线程 /// </summary> public static void TaskRun(this System.Windows.Forms.Control ctrl, Action<Action<Action>> action) { System.Threading.ThreadPool.QueueUserWorkItem(delegate { action.Invoke(b => ctrl.Invoke(b)); }); }}

January 16, 2021 · 1 min · jiezi

关于c:Linux学习Linux基础简介

这一节,咱们将简略介绍一下Linux。1:Linux同windows是一样的,都是操作系统的一种,都给咱们提供一个平台去开发或者执行某些程序。能够说Linux零碎也是软件的一种,不要将他想的太过于神秘。(注:通常咱们所说的什么零碎都是内核+软件形成的) 2:接下来咱们简略介绍一下Linux的倒退历史 Linux是一套自在加凋谢源代码的类Unix操作系统,诞生于1991年10月5日(第一次正式向外颁布),由芬兰学生Linus Torvalds和起初陆续退出的泛滥爱好者共同开发实现。 Linux是一个基于POSIX和Unix的多用户、多任务、反对多线程和多CPU的操作系统。它能运行次要的Unix工具软件、应用程序和网络协议,可反对32位和64位硬件。Linux继承了Unix以网络为外围的设计思维,是一个性能稳固的多用户网络操作系统。 Linux存在着许多不同的版本,但它们都应用了Linux内核。Linux可装置在各种计算机硬件设施中,比方:手机、平板电脑、路由器、视频游戏控制台、台式计算机、大型机和超级计算机。 如果想理解具体的信息请本人查找一下3:咱们在这里说一下Linux的系统结构,以便于从大方向理解Linux的零碎。 a:之前说了,Linux零碎能够作为一种软件,提供程序运行的化境,咱们将之成为内核。学过单片机的人都是到,咱们最底层是有很简略的各种小程序形成,例如咱们用汇编语言写一 些小的程序去管制硬件的某些行为(也就是高下点平,这里不做过多介绍)。而咱们的Linux零碎就是管制咱们硬件所有的资源,对这些资源进行批准的调配性能,咱们的软件是可能 通过一些调用去应用这些资源。 b:在Linux中,咱们写一些函数须要调用内核来实现,这里咱们将调用内核实现这中操作叫做零碎调用。 三种形式进行零碎调用:shell、 库函数(全副建设在零碎给的接口上)、 间接调用。(如下图所示)。 4:在这里咱们介绍一下对于登录Linux进行的操作。 用户在登录的时候须要先后输出登录名和登录的用户明码,而这个用户名和用户明码通常是存在/etc/passwd文件下,这个文件每一行都是一个用户,其中登录项由7个冒号分隔开来。 他们别离是登录名、加密口令、用户数值ID、用户数值组ID、正文字段、其实目录和用户应用的SHELL程序。后面咱们说shell能够用来和Linux进行交互,因而咱们能够配置本人的shell 程序,这样更改不便咱们的应用。通常默认的shell程序是bash,我喜爱用zsh程序,无关zsh的配置请参考如下连贯https://blog.csdn.net/towedjfiowaj/article/details/112691257 5:接下来咱们简略介绍一下文件和目录 在Linux中或者unix中能够成为所有皆文件,因而理解Linux中的文件和目录是非常有必要的。 在windows中,咱们能够将磁盘划分为c盘、d盘等。然而在Linux中、咱们只有一个磁盘,而这个磁盘是从/(根)目录开始的,其余的都是以各种形式进行挂载。 咱们这里说介绍文件和目录,其实每个目录能够了解为蕴含多个目录项的文件,如果不信的话能够应用vim dirname去关上一个目录,你就发下外面存储了许多目录项/文件。 在Linux中文件中还蕴含文件的属性信息,文件属性有文件大小、文件类型、文件所有者、文件权限、文件的批改工夫等。这些属性咱们stat或者fstat进行获取。 在这里我阐明一下文件类型(在执行ls -l时候如下图1就能够辨别文件各种信息了,其中文件类型前面九个字符别离是所有者:所属组:其他人对该文件的读写和执行权限): 文件类型:一般文件(-)、目录(d)、管道(p)、链接文件(l)字符设施文件(c)、 块设施文件(b)、 套接字(s)。 文件名:在Linux呈现文件名的字符除了/和null,前者用于宰割目录、后者用于完结一个目录。当然在失常的状况下,尽量只应用印刷字符集,免得引起不必要的麻烦。 同时咱们在创立目录的时候,会主动创立两个.和..目录,这两个目录别离代表当前目录和上一级目录。 路径名:门路分为绝对路径和相对路径。绝对路径是从根目录开始的,例子:/etc/passwd。绝对目录是从当前目录开始的目录./../passwd。 在这里介绍一下如何失去路径名:如上面一个小程序就是读取指定目录下的所有内容。 #include <dirent.h> #inlcude <stdio.h> int main(int argc, char* argv[]) { DIR *dp; struct dirent *dirp; if(argc != 2) { return 0; } if((dp = opendir(argv[1])) == NULL) { return 0; } while((dirp = readdir(dp)) != NULL) { printf("%s\n", dirp->d_name); } } 对于这个程序只有两点须要了解两个其中两个函数就能够。 工作目录:每一个执行的过程都会一个工作目录。所说的相对路径都是绝对于当前工作目录而定的。 起始目录:也就是当咱们登录到零碎是坐在的目录。 5:接下来介绍一下Linux中无关的输出和输入。 ...

January 16, 2021 · 1 min · jiezi

关于c#:进击吧Blazor第一章-1初识-Blazor

作者介绍陈超超Ant Design Blazor 我的项目贡献者领有十多年从业教训,长期基于.Net技术栈进行架构与开发产品的工作,Ant Design Blazor 我的项目贡献者,现就职于正泰团体 第一次写专栏,结尾不晓得说什么,所以……先来段广告????《进击吧!Blazor!》是自己与张善友老师单干的Blazor零根底入门系列视频,此系列能让一个从未接触过Blazor的程序员把握开发Blazor利用的能力。视频地址:https://space.bilibili.com/48...本系列文章是基于《进击吧!Blazor!》直播内容编写,降级.Net5,改良问题,解说更全面。系列文章目录第一章 初出江湖 —— ToDo利用开发练手初识 BlazorHello Blazor页面制作数据交互组件开发平安 第二章 仗剑江湖 —— 企业组织绩效数据管理平台开发实战我的项目框架搭建指标保护:增删改查组织机构保护:树数据采集:自定义表格指标剖析:Chart账号与权限站点部署

January 16, 2021 · 1 min · jiezi

关于c#:C中的异步和多线程

许多开发人员对异步代码和多线程以及它们的工作原理和应用办法都有谬误的意识。在这里,你将理解这两个概念之间的区别,并应用c#实现它们。 我:“服务员,这是我第一次来这家餐厅。通常须要4个小时能力拿到食物吗?” 服务员:“哦,是的,学生。这家餐厅的厨房里只有一个厨师。” 我:“……只有一个厨师吗?” 服务员:“是的,学生,咱们有好几个厨师,但每次只有一个在厨房工作。” 我:“所以其余10个衣着厨师服站在厨房里的人……什么都不做吗?厨房太小了吗?” 服务员:“哦,咱们的厨房很大,学生。” 我:“那为什么他们不同时工作呢?” 服务员:“学生,这倒是个好主见,但咱们还没想好怎么做。” 我:“好了,奇怪。然而…嘿…当初的主厨在哪里?我当初没看见有人在厨房里。” 服务员:“是的,学生。有一份订单的厨房用品曾经用完了,所以厨师曾经进行烹饪,站在里面等着送货了。” 我:“看起来他能够一边等一边做饭,兴许送货员能够间接通知他们什么时候到了?” 服务员:“又是一个绝妙的主见,学生。咱们在前面有送货门铃,但厨师喜爱等。我去给你再拿点水来。” 多蹩脚的餐厅,对吧?可怜的是,很多程序都是这样工作的。 有两种不同的办法能够让这家餐厅做得更好。 首先,很显著,每个独自的晚餐订单能够由不同的厨师来解决。每一种都是一个必须按特定程序产生的事件列表(筹备原料,而后混合它们,而后烹饪,等等)。因而,如果每个厨师都致力于解决这一清单上的货色,几份晚餐订单能够同时做出。 这是一个真实世界中的多线程示例。计算机有能力让多个不同的线程同时运行,每个线程负责按特定程序执行一系列流动。 而后还有异步行为。须要明确的是,异步不是多线程的。还记得那个始终在等外卖的厨师吗?真是浪费时间!在期待的过程中,他没有做任何有意义的事件,比方做饭。而且,期待也不会让送货更快。一旦他打电话订购供应品,发货就会随时产生,所以为什么要等呢?相同,送货员只需按门铃,说一句:“嘿,这是你的供应品!” 有很多I/O流动是由代码之外的货色解决的。例如,向近程服务器发送一个网络申请。这就像给餐厅点餐一样。你的代码所做的惟一事件就是进行调用并接管后果。如果抉择期待后果,在这两者之间齐全不做任何事件,那么这就是“同步”行为。 然而,如果你更喜爱在后果返回时被打断/告诉(就像送货员达到时按门铃),同时能够解决其余事件,那么这就是“异步”行为。 只有工作是由不受以后代码间接管制的对象实现的,就能够应用异步代码。例如,当你向硬盘驱动器写入一堆数据时,你的代码并没有执行理论的写入操作。它只是申请硬件执行该工作。因而,你能够应用异步编码开始编写,而后在编写实现时失去告诉,同时持续解决其余事件。 异步的长处在于不须要额定的线程,因而十分高效。 “等等!”你说。“如果没有额定的线程,那么谁或什么在期待后果?代码如何晓得返回的后果?” 还记得那个门铃吗?你的电脑里有一个零碎叫做“中断”零碎,它的工作原理有点像那个门铃。当你的代码开始一个异步流动时,它基本上会装置一个虚构的门铃。当其余工作(写入硬盘驱动器,期待网络响应等)实现时,中断零碎“中断”以后运行的代码并按下门铃,让你的应用程序晓得有一个工作在期待!不须要线程坐在那里期待! 让咱们疾速回顾一下咱们的两种工具: 多线程:应用一个额定的线程来执行一系列流动/工作。 异步:应用同一个线程和中断零碎,让线程外的其余组件实现一些流动,并在流动完结时失去告诉。 UI线程还有一件重要的事件须要晓得的是为什么应用这些工具是好的。在.net中,有一个主线程叫做UI线程,它负责更新屏幕的所有可视局部。默认状况下,这是所有运行的中央。当你点击一个按钮,你想看到按钮被短暂地按下,而后返回,这是UI线程的责任。你的利用中只有一个UI线程,这意味着如果你的UI线程忙着做沉重的计算或期待网络申请之类的事件,那么它不能更新你在屏幕上看到的货色,直到它实现。后果是,你的应用程序看起来像“解冻”——你能够点击一个按钮,但仿佛什么都不会产生,因为UI线程正在忙着做其余事件。 现实状况下,你心愿UI线程尽可能地闲暇,这样你的应用程序仿佛总是在响应用户的操作。这就是异步和多线程的由来。通过应用这些工具,能够确保在其余中央实现沉重的工作,UI线程保持良好和响应性。 当初让咱们看看如何在c#中应用这些工具。 C#的异步操作执行异步操作的代码非常简单。你应该晓得两个次要的关键字:“async”和“await”,所以人们通常将其称为async/await。假如你当初有这样的代码: public void Loopy(){ var hugeFiles = new string[] { "Gr8Gonzos_Home_Movie_In_8k_Res.mkv", // 1 GB "War_And_Peace_In_150_Languages.rtf", // 1.2 GB "Cats_On_Catnip.mpg" // 0.9 GB }; foreach (var hugeFile in hugeFiles) { ReadAHugeFile(hugeFile); } MessageBox.Show("All done!");}public byte[] ReadAHugeFile(string bigFile){ var fileSize = new FileInfo(bigFile).Length; // Get the file size var allData = new byte[fileSize]; // Allocate a byte array as large as our file using (var fs = new System.IO.FileStream(bigFile, FileMode.Open)) { fs.Read(allData, 0, (int)fileSize); // Read the entire file... } return allData; // ...and return those bytes!}在以后的模式中,这些都是同步运行的。如果你点击一个按钮从UI线程运行Loopy(),那么应用程序将仿佛解冻,直到所有三大文件浏览,因为每个“ReadAHugeFile”是要花很长时间在UI线程上运行,并将同步浏览。这可不好!让咱们看看是否将ReadAHugeFile变为异步的这样UI线程就能持续解决其余货色。 ...

January 16, 2021 · 2 min · jiezi

关于c:Linux好用的vim超级配置zsh配置完整版

1:介绍vim vim是用于Linux下编译代码的工具,具备肯定的补全性能,然而与咱们配置的相比就要差商许多了。在这里、我首先介绍如何配置vimplus(是一款十分好用的vim配置)。之后我再介绍zsh的配置,zsh是一种shell脚本,是咱们和Linux交互的工具。 vimplus的装置只须要执行几个命令就能够,非常简单。 cd ~。 sudo git clone https://github.com/chxuan/vimplus.git ~/.vimplus. cd ~/.vimplus ./install.sh 这样,弱小的vim配置就装置实现了。在这里须要留神的是,如果你没有git这个工具,能够应用sudo apt install git 命令进行装置。如果你的apt源配置谬误,也就是在保障你能够失常连贯网络的状况下不可能下载这个工具,请关上这个链接[https://developer.aliyun.com/mirror/ubuntu?spm=a2c6h.13651102.0.0.3e221b11vU4mtw]() 这是一个阿里源的地址,点击就能够下载。好了对于vim的配置我这里就介绍这么多。 2:介绍zsh的相干配置。 在这里介绍我的zsh配置,之前说过了,zsh是咱们和Linux交互的命令工具。 首先、第一点须要确定的是你有没有zsh这个工具,如果你没有zsh这个工具请应用sudo apt install zsh进行装置。 第二点就是咱们的zsh配置了,咱们能够在本人的家目录下进行配置,首先咱们创立一个.zshrc这个文件,此文件是咱们这个用户登陆的时候zsh读取的配置文件。 最初一点,我将zsh配置连贯放到这里,间接应用下述命令装置即可。 git clone https://github.com/spicycode/ze-best-zsh-config.git 目录 如果下载下来的是压缩包,请解压,而后将其中的暗藏文件拷贝到家目录下,也就是~目录下。 最初我将我改过的.zshrc文件贴到这里,我改的文件是依据这个下载内容进行更改整合的,因为下载的货色不可能齐全应用。 之后在家目录创立.zshrc文件,将下述内容增加到.zshrc文件中,之后应用命令sourc .zshrc就能够失效了,如果还没有失效的话,请退出Linux从新登录。 if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi export PATH=bin:script:.bin:$PATH precmd() { if [[ -n "$TMUX" ]]; then tmux setenv "$(tmux display -p 'TMUX_PWD_#D')" "$PWD" fi } # 别名局部,这部分依据本人的爱好进行甚至 alias la='ls -a' alias lc='ls *.c' alias sl='ls' alias ll='ls -l' alias grepn='grep -nrE ./' alias findn='find ./ -name' alias rm='rm -i' alias cpr='cp -r' alias rmd='rm -r' alias v.z='vim ~/.zshrc' alias s.z='source ~/.zshrc' # color 局部内容 autoload colors; colors # The variables are wrapped in %{%}. This should be the case for every # variable that does not contain space. for COLOR in RED GREEN YELLOW BLUE MAGENTA CYAN BLACK WHITE; do eval PR_$COLOR='%{$fg_no_bold[${(L)COLOR}]%}' eval PR_BOLD_$COLOR='%{$fg_bold[${(L)COLOR}]%}' done eval RESET='$reset_color' export PR_RED PR_GREEN PR_YELLOW PR_BLUE PR_WHITE PR_BLACK export PR_BOLD_RED PR_BOLD_GREEN PR_BOLD_YELLOW PR_BOLD_BLUE export PR_BOLD_WHITE PR_BOLD_BLACK # Clear LSCOLORS unset LSCOLORS export CLICOLOR=1 export LS_COLORS=exfxcxdxbxegedabagacad # 绑定某些按键 # To see the key combo you want to use just do: # cat > /dev/null # And press it bindkey "^K" kill-whole-line # ctrl-k bindkey "^R" history-incremental-search-backward # ctrl-r bindkey "^A" beginning-of-line # ctrl-a bindkey "^E" end-of-line # ctrl-e bindkey "[B" history-search-forward # down arrow bindkey "[A" history-search-backward # up arrow bindkey "^D" delete-char # ctrl-d bindkey "^F" forward-char # ctrl-f bindkey "^B" backward-char # ctrl-b bindkey -e # Default to standard emacs bindings, regardless of editor string # 定义某些全局变量 # Currently this path is appendend to dynamically when picking a ruby version export PATH=node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/local/share/npm/bin:~/.cabal/bin:~/.local/bin:$PATH export PATH=$PATH:/opt/boxen/homebrew/opt/go/libexec/bin # Setup terminal, and turn on colors export TERM=xterm-256color export CLICOLOR=1 export LSCOLORS=Gxfxcxdxbxegedabagacad # Enable color in grep export GREP_OPTIONS='--color=auto' export GREP_COLOR='3;33' # This resolves issues install the mysql, postgres, and other gems with native non universal binary extensions export ARCHFLAGS='-arch x86_64' export LESS='--ignore-case --raw-control-chars' export PAGER='most' export EDITOR='vim' export PYTHONPATH=/usr/local/lib/python2.6/site-packages # CTAGS Sorting in VIM/Emacs is better behaved with this in place export LC_COLLATE=C # GitHub token with no scope, used to get around API limits #xport HOMEBREW_GITHUB_API_TOKEN=$(cat ~/.gh_api_token) # setopt 某些选项设置 # ===== Basics # If you type foo, and it isn't a command, and it is a directory in your cdpath, go there setopt AUTO_CD # Allow comments even in interactive shells (especially for Muness) # setopt INTERACTIVE_COMMENTS # ===== History # Allow multiple terminal sessions to all append to one zsh command history setopt APPEND_HISTORY # Add comamnds as they are typed, don't wait until shell exit setopt INC_APPEND_HISTORY # Do not write events to history that are duplicates of previous events setopt HIST_IGNORE_DUPS # When searching history don't display results already cycled through twice setopt HIST_FIND_NO_DUPS # Remove extra blanks from each command line being added to history setopt HIST_REDUCE_BLANKS # Include more information about when the command was executed, etc setopt EXTENDED_HISTORY # ===== Completion # Allow completion from within a word/phrase setopt COMPLETE_IN_WORD # When completing from the middle of a word, move the cursor to the end of the word setopt ALWAYS_TO_END # ===== Prompt # Enable parameter expansion, command substitution, and arithmetic expansion in the prompt setopt PROMPT_SUBST unsetopt MENU_COMPLETE setopt AUTO_MENU # 历史设置 HISTSIZE=10000 SAVEHIST=10000 HISTFILE=~/.zsh_history bindkey '^R' zaw-history function git_prompt_info { local ref=$(=git symbolic-ref HEAD 2> /dev/null) local gitst="$(=git status 2> /dev/null)" if [[ -f .git/MERGE_HEAD ]]; then if [[ ${gitst} =~ "unmerged" ]]; then gitstatus=" %{$fg[red]%}unmerged%{$reset_color%}" else gitstatus=" %{$fg[green]%}merged%{$reset_color%}" fi elif [[ ${gitst} =~ "Changes to be committed" ]]; then gitstatus=" %{$fg[blue]%}!%{$reset_color%}" elif [[ ${gitst} =~ "use \"git add" ]]; then gitstatus=" %{$fg[red]%}!%{$reset_color%}" elif [[ -n `git checkout HEAD 2> /dev/null | grep ahead` ]]; then gitstatus=" %{$fg[yellow]%}*%{$reset_color%}" else gitstatus='' fi if [[ -n $ref ]]; then echo "%{$fg_bold[green]%}/${ref#refs/heads/}%{$reset_color%}$gitstatus" fi } PROMPT='%~%<< $(git_prompt_info)${PR_BOLD_WHITE}>%{${reset_color}%} ' precmd() { if [[ -n "$TMUX" ]]; then tmux setenv "$(tmux display -p 'TMUX_PWD_#D')" "$PWD" fi }本文由博客群发一文多发等经营工具平台 OpenWrite 公布

January 16, 2021 · 4 min · jiezi

关于c:dhcp10源码分析讲解dhcpd的源码流程

1:首先阐明dhcpd代码下载方式,请参考我这篇文章dhcp源码下载2:接下来咱们解析dhcp源码。(这里只是大体介绍dhcp源码) a:首先咱们来剖析各个目录中的文件。 如图1所示有如下的各种文件。 alloc.c文件时管制内存的操作,咱们在其余文件中应用申请和开释内存都是通过这个文件中的函数来实现。 confpars文件用于解析配置文件内容的文件。也就是说,当咱们读取配置文件时,咱们调用这个文件中的函数 来接写配置文件中的内容。 dhcpd.c文件时DHCP服务程序的主流程管制,咱们次要剖析这个文件中的源码。 options.c文件用于解析咱们的option的,能够通过man手册查看dhcpd的option。(eg:man dhcpd) socket.c是对套接字的封装,用于传递包的。 convert.c用于对一些类型的转换。 dhcpxlt.c同样用于对一些地址进行转换。 inet.c用于对网络地址进行转换。 packet.c用于对包的解决。 tables.c是一些表的治理(eg:dhcp硬件类型、option。咱们解析一些内容的时候回去这些表中进行查问)。 bpf.c:对于套解析一些ioctl设置(eg:设置关上的套接字传输速率)。 db.c:是对DHCP数据库的治理,也就是说将一些数据存储到文件中进行治理。 dispatch.c:这个文件设置。 memory.c:对dhcp用到的内存进行治理,例如咱们动静租任的IP print.c:打印一些信息。 tree.c conflex.c errwarn.c:谬误和正告信息 raw.c:包的发送 upf.c:同样也是包的解决。 图1 b:在这里咱们先剖析一下DHCP包的内容,如图所示DHCP包的内容。如图1所示。option字段如图2所示OP:报文的操作类型。分为申请报文和响应报文。1:申请报文,2:应答报文。即client送给server的封包,设为1,反之为2。申请报文: DHCP Discover、DHCP Request、DHCP Release、DHCP Inform和DHCP Decline。应答报文: DHCP Offer、DHCP ACK和DHCP NAK。Htype: DHCP客户端的MAC地址类型。 MAC地址类型其实是指明网络类型 ,Htype值为1时示意为最常见的以太网 MAC地址类型。Hlen: DHCP客户端的MAC地址 长度。以太网MAC地址长度为6个字节,即以太网时Hlen值为6。Hops:DHCP报文通过的DHCP中继的数目,默认为0。DHCP申请报文每通过一个DHCP中继,该字段就会减少1。没有通过DHCP中继时值为0。( 若数据包需通过router传送,每站加1,若在同一网内,为0。 )Xid:客户端通过DHCP Discover报文发动一次IP地址申请时抉择的随机数,相当于申请标识。用来标识一次IP地址申请过程。在一次申请中所有报文的Xid都是一样的。Secs:DHCP客户端从获取到IP地址或者续约过程开始到当初所耗费的工夫,以秒为单位。在没有取得IP地址前该字段始终为0。( DHCP客户端开始DHCP申请后所通过的工夫。目前尚未应用,固定为0。)Flags:标记位,只应用第0比特位,是播送应答标识位,用来标识DHCP服务器应答报文是采纳单播还是播送发送,0示意采纳单播发送形式,1示意采纳播送发送形式。其余位 尚未应用 。(即 从0-15bits,最左1bit为1时示意server将以播送形式传送封包给client。 )【留神】在客户端正式调配了IP地址之前的第一次IP地址申请过程中,所有DHCP报文都是以播送形式发送的,包含客户端发送的DHCP Discover和DHCP Request报文,以及DHCP服务器发送的DHCP Offer、DHCP ACK和DHCP NAK报文。当然,如果是由DHCP中继器转的报文,则都是以单播形式发送的。另外,IP地址续约、IP地址开释的相干报文都是采纳单播形式进行发送的。Ciaddr:DHCP客户端的IP地址。仅在DHCP服务器发送的ACK报文中显示,在其余报文中均显示0,因为在失去DHCP服务器确认前,DHCP客户端是还没有调配到IP地址的。只有客户端是Bound、Renew、Rebinding状态,并且能响应ARP申请时,能力被填充。Yiaddr:DHCP服务器调配给客户端的IP地址。仅在DHCP服务器发送的Offer和ACK报文中显示,其余报文中显示为0。Siaddr:下一个为DHCP客户端调配IP地址等信息的DHCP服务器IP地址。仅在DHCP Offer、DHCP ACK报文中显示,其余报文中显示为0。( 用于bootstrap过程中的IP地址)Giaddr:DHCP客户端发出请求报文后通过的第一个DHCP中继的IP地址。如果没有通过DHCP中继, 则显示为0。( 转发代理(网关)IP地址 )Chaddr:DHCP客户端的MAC地址。在每个报文中都会显示对应DHCP客户端的MAC地址。Sname:为DHCP客户端调配IP地址的DHCP服务器名称(DNS域名格局)。在Offer和ACK报文中显示发送报文的DHCP服务器名称,其余报文显示为0。File:DHCP服务器为DHCP客户端指定的启动配置文件名称及门路信息。仅在DHCP Offer报文中显示,其余报文中显示为空。Options: 可选项字段,长度可变,格局为"代码+长度+数据"。 c:接下来我这里介绍一下DHCP次要流程调用,如下图1所示 这里次要是指文件之间的调用,不做具体介绍。在接下来的局部会做具体介绍。(对于存储客户数据局部同样不做具体介绍,只是对主题流程做一些具体的介绍)。我当初这里列出这个文件中的函数: dhcpd.c#ifndef lintstatic char ocopyright[] ="$Id: dhcpd.c,v 1.36.2.1 1997/03/29 08:11:03 mellon Exp $ Copyright 1995, 1996 The Internet Software Consortium.";#endif//这部分能够不必管,因为这部分是对版权和一些音讯的定义。用到时权当字符串应用就能够了。static char copyright[] ="Copyright 1995, 1996 The Internet Software Consortium.";static char arr [] = "All rights reserved.";static char message [] = "Internet Software Consortium DHCPD $Name: V1-0-0 $";/***这里我阐明这个dhcpd.h头文件这个头文件定义了所有对于dhcp用到的函数,和一些公共的全局变量等***/#include "dhcpd.h"//这个函数次要是在解析参数的时候显示一些应用的配置信息static void usage PROTO ((void));//如函数名字所示,次要是获取以后的工夫信息。TIME cur_time;//用于保留一些公共成员,如最大租任的工夫等,具体的看头文件中的变量名字即可。struct group root_group;//服务端的以太网地址。struct iaddr server_identifier;int server_identifier_matched; #ifdef USE_FALLBACK//定义接口的信息,在应用fallback时候。具体的我也不是很分明,这里只是剖析代码。//如果想分明具体性能的时候,请参考rfcDHCP文档。struct interface_info fallback_interface;#endif//服务端的端口u_int16_t server_port;//定义log的优先级,不同的优先级打印显示音讯是不同的。{eg,在有缓冲区输入的状况下,优先级高的可能不期待缓冲区满就间接输入,例如stderror就是间接输入。而优先级低的可能须要期待缓冲区满再输入}int log_priority;//在debug的状况下,定义log_perror,这可可能影响一些输入。#ifdef DEBUGint log_perror = -1;#elseint log_perror = 1;#endif//这里是一些配置文件的门路。如下别离是配置文件、数据存储文件、过程id文件。char *path_dhcpd_conf = _PATH_DHCPD_CONF;char *path_dhcpd_db = _PATH_DHCPD_DB;char *path_dhcpd_pid = _PATH_DHCPD_PID;//main函数,程序的入口,这个main函数中次要负责读取配置文件,初始化一些参数,之后调用外围dispatch函数用于ip的散发。int main (argc, argv, envp) int argc; char **argv, **envp;{ int i, status; struct servent *ent; char *s;#ifndef DEBUG int pidfilewritten = 0; int pid; char pbuf [20]; int daemon = 1;#endif //这一部分次要是显示一些音讯,对于剖析DHCP主流程无关紧要。然而如果想要剖析DHCP的log工作原理,就非常重要了。 /* Initially, log errors to stderr as well as to syslogd. */#ifdef SYSLOG_4_2 openlog ("dhcpd", LOG_NDELAY); log_priority = DHCPD_LOG_FACILITY;#else openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);#endif#ifndef DEBUG#ifndef SYSLOG_4_2 setlogmask (LOG_UPTO (LOG_INFO));#endif#endif note (message); note (copyright); note (arr); //在这里次要是对命令行参数进行解析,依据不同的参数进行不同的初始化操作。具体的能够参考man dhcp进行比拟看。 //在这里我举一个例子,-d选项用于debug,如果咱们指定-d选项那么咱们将显示一些debug信息。 for (i = 1; i < argc; i++) { if (!strcmp (argv [i], "-p")) { if (++i == argc) usage (); for (s = argv [i]; *s; s++) if (!isdigit (*s)) error ("%s: not a valid UDP port", argv [i]); status = atoi (argv [i]); if (status < 1 || status > 65535) error ("%s: not a valid UDP port", argv [i]); server_port = htons (status); debug ("binding to user-specified port %d", ntohs (server_port)); } else if (!strcmp (argv [i], "-f")) {#ifndef DEBUG daemon = 0;#endif } else if (!strcmp (argv [i], "-d")) {#ifndef DEBUG daemon = 0;#endif log_perror = -1; } else if (!strcmp (argv [i], "-cf")) { if (++i == argc) usage (); path_dhcpd_conf = argv [i]; } else if (!strcmp (argv [i], "-lf")) { if (++i == argc) usage (); path_dhcpd_db = argv [i]; } else if (argv [i][0] == '-') { usage (); } else { struct interface_info *tmp = ((struct interface_info *) dmalloc (sizeof *tmp, "get_interface_list")); if (!tmp) error ("Insufficient memory to %s %s", "record interface", argv [i]); memset (tmp, 0, sizeof *tmp); strcpy (tmp -> name, argv [i]); tmp -> next = interfaces; tmp -> flags = INTERFACE_REQUESTED; interfaces = tmp; } }#ifndef DEBUG if (daemon) { /* First part of becoming a daemon... */ if ((pid = fork ()) < 0) error ("Can't fork daemon: %m"); else if (pid) exit (0); } /* Read previous pid file. */ if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) { status = read (i, pbuf, (sizeof pbuf) - 1); close (i); pbuf [status] = 0; pid = atoi (pbuf); /* If the previous server process is not still running, write a new pid file immediately. */ if (pid && kill (pid, 0) < 0) { unlink (path_dhcpd_pid); if ((i = open (path_dhcpd_pid, O_WRONLY | O_CREAT, 0640)) >= 0) { sprintf (pbuf, "%d\n", (int)getpid ()); write (i, pbuf, strlen (pbuf)); close (i); pidfilewritten = 1; } } }#endif /* !DEBUG */ /* Default to the DHCP/BOOTP port. */ //在这里如果没有指定端口号的环,咱们将通过函数获取端口好的一些信息,当然默认是67。 if (!server_port) { ent = getservbyname ("dhcp", "udp"); if (!ent) server_port = htons (67); else server_port = ent -> s_port; endservent (); } //很容易了解,获取以后的工夫 /* Get the current time... */ GET_TIME (&cur_time); /* 读取配置文件,在之后的会剖析这个函数 */ if (!readconf ()) error ("Configuration file errors encountered -- exiting"); /* 对数据库做一些初始化操作 */ db_startup (); /* discover所有网络,并且初始化他们 */ discover_interfaces (1);#ifndef DEBUG /* If we were requested to log to stdout on the command line, keep doing so; otherwise, stop. */ if (log_perror == -1) log_perror = 1; else log_perror = 0; if (daemon) { /* Become session leader and get pid... */ close (0); close (1); close (2); pid = setsid (); } /* If we didn't write the pid file earlier because we found a process running the logged pid, but we made it to here, meaning nothing is listening on the bootp port, then write the pid file out - what's in it now is bogus anyway. */ if (!pidfilewritten) { unlink (path_dhcpd_pid); if ((i = open (path_dhcpd_pid, O_WRONLY | O_CREAT, 0640)) >= 0) { sprintf (pbuf, "%d\n", (int)getpid ()); write (i, pbuf, strlen (pbuf)); close (i); pidfilewritten = 1; } }#endif /* !DEBUG */ /* 这个函数将进行接管包,并且散发ip地址*/ dispatch (); /* Not reached */ return 0;}/* 此函数用于打印一些应用的信息,在参数中能够指定显示实用信息,程序就会显示一些应用信息 */static void usage (){ error ("Usage: dhcpd [-p <UDP port #>] [-d] [-f] [-cf config-file]%s", "\n [-lf lease-file] [if0 [...ifN]]");}//此函数临时没有用到void cleanup (){}图1 ...

January 16, 2021 · 9 min · jiezi

关于c#:项目实战C上位机arduino下位机控制点亮LED灯

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/112651809 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) 开发专栏:我的项目实战 前言 以后比拟风行的arduino开发,联动做一个Demo。 利用构架 上位机:C#上位机通过串口发送接管控制协议,来管制下位机; 下位机:arduino下位机主控,承受上位机串口协定管制GPIO硬件引脚; 硬件电路:面包板LED串220R电路,以arduino引脚驱动; Demo arduino开发板 硬件电路连贯 若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/112651809

January 15, 2021 · 1 min · jiezi

关于c++:c关键字typeid

typeid是c++的一个关键字,typeid操作符的返回后果是规范库类型type_info对象的援用。然而,C++规范并没有明确定义type_info,其具体实现依赖于各个编译器。规范只规定了typeid操作符必须实现如下四种操作:操作阐明t1 == t2如果两个对象t1和t2类型雷同,则返回true;否则返回falset1 != t2如果两个对象t1和t2类型不同,则返回true;否则返回falset.name()返回类型的C-style字符串。由编译器决定,不肯定就是实在的类型名t1.before(t2)判断t1是否位于t2的后面。类型排列程序与编译器相干,基类不肯定位于派生类的后面。type_info的成员函数name返回类型的C-style字符串,但这个返回的类型名与程序中应用的相应类型名不肯定统一,其返回值的实现由编译器决定,规范只要求每个类型返回的字符串是惟一的。和sizeof操作符相似,typeid的操作对象既能够是数据类型,也能够是表达式。应用typeid判断各种类型示例代码如下:#include<iostream> #include <typeinfo> using namespace std; class Base{};class Derived:public Base{};void func1();int func2(int n);int main() { int a = 10; int* b = &a; float c; double d; cout << typeid(a).name() << endl; cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; cout << typeid(d).name() << endl; cout << typeid(Base).name() << endl; cout << typeid(Derived).name() << endl; cout << typeid(func1).name() << endl; cout << typeid(func2).name() << endl;} Mac下应用clang++编译运行后果如下:iPifd4Base7DerivedFvvEFiiE不像Java、C#等动静语言,C++运行时能获取到的类型信息十分无限,规范也定义的很含糊,如同“鸡肋”个别。在理论工作中,咱们个别只应用type_info的“==”运算符来判断两个类型是否雷同。再来看看上面的示例代码:#include<iostream> #include <typeinfo> using namespace std; class Base{};class Drived: public Base{};int main(){ Base* pb; Drived d; pb = &d; if(strcmp(typeid(*pb).name(), typeid(Base).name()) == 0) { cout << "this is Base" << endl; } else if(strcmp(typeid(*pb).name(), typeid(Drived).name()) == 0) { cout << "this is Drived" << endl; } if(strcmp(typeid(d).name(), typeid(Base).name()) == 0) { cout << "this is Base" << endl; } else if(strcmp(typeid(d).name(), typeid(Drived).name()) == 0) { cout << "this is Drived" << endl; }}Mac下应用clang++编译运行后果如下:this is Basethis is Drived从运行后果中能够看出,即应用基类指针指向派生类,但应用typeid判断的基类指针类型仍然是基类指针。因而咱们不能用typeid来判断基类指针理论指向的是否是某个派生类。

January 15, 2021 · 1 min · jiezi

关于c#:WPF平台开发-如何将树编辑器添加到数据网格单元中

点击获取工具>> 问题试图将树编辑器嵌入具备多选性能的网格单元中,如何将视图模型SelectedPerils绑定到弹出树控件中的已查看我的项目? 解决方案据理解,目前的指标是应用带有TreeListView的弹出式编辑器来编辑汇合属性,本文将为大家解释此操作所须要的步骤。 GridControl不反对编辑应用FieldName绑定的汇合属性,您能够更改属性申明,以便它应用对象类型或应用Binding而不是FieldName。请参阅Binding Columns to Data Source Fields,让咱们应用第一个选项:C# `public object SelectedPerils { get; set; }//...SelectedPerils = new List<Peril>();//...((List<Peril>)Portfolios[0].SelectedPerils).Add(Portfolios[0].Perils[0]);((List<Peril>)Portfolios[1].SelectedPerils).Add(Portfolios[1].Perils[1]);((List<Peril>)Portfolios[2].SelectedPerils).Add(Portfolios[2].Perils[0]);` XAML <dxg:GridColumn FieldName="SelectedPerils" /> 咱们倡议应用LookUpEdit在弹出窗口中显示GridControl,应用MultiSelectLookUpEditStyleSettings为其启用多选性能,这是执行此操作的预定义方法。因为您心愿将其默认TableView替换为TreeListView,因而须要申明CellTemplate和PopupContentTemplate:XAML `<dxg:GridColumn FieldName="SelectedPerils"><dxg:GridColumn.CellTemplate><DataTemplate><dxg:LookUpEditDisplayMember="Name"ItemsSource="{Binding RowData.Row.Perils}"Name="PART_Editor"><dxg:LookUpEdit.PopupContentTemplate><ControlTemplate><dxg:GridControl Name="PART_GridControl" SelectionMode="MultipleRow"><dxg:GridControl.View><dxg:TreeListView KeyFieldName="ID" ParentFieldName="ParentID" /></dxg:GridControl.View></dxg:GridControl></ControlTemplate></dxg:LookUpEdit.PopupContentTemplate><dxg:LookUpEdit.StyleSettings><dxg:MultiSelectLookUpEditStyleSettings /></dxg:LookUpEdit.StyleSettings></dxg:LookUpEdit></DataTemplate></dxg:GridColumn.CellTemplate></dxg:GridColumn>` 您的编辑器应该可能抉择嵌套值,因而您须要应用自参考数据结构,这就是为什么在模板中应用KeyFieldName和ParentFieldName属性的起因。 否则,您的LookUpEdit将回绝其ItemsSource之外的值,因为在那里应用DisplayMember 并关上了查找模式。C# `public class Peril {public int ID { get; set; }public int ParentID { get; set; } = -1;//...}//...Perils = new List<Peril>{new Peril { Name = "Earthquake", ID = 0},new Peril { Name = "EQ", ID = 10, ParentID = 0 },new Peril { Name = "FF", ID = 11, ParentID = 0 },new Peril { Name = "Hurricane", ID = 1},new Peril { Name = "HU", ID = 12, ParentID = 1 },new Peril { Name = "TC", ID = 13, ParentID = 1 },new Peril { Name = "Tornado Hail", ID = 2},new Peril { Name = "TH", ID = 14, ParentID = 2 },new Peril { Name = "WS", ID = 15, ParentID = 2 },};` ...

January 15, 2021 · 1 min · jiezi

关于c++:C的各种编译错误

error C2760:语法错误: 意外的令牌“标识符”,预期的令牌为“类型说明符”解决办法: C/C++ -> 语言 -> 合乎模式,批改为否

January 15, 2021 · 1 min · jiezi

关于c#:ASPNET-Core中的数据保护

在这篇文章中,我将介绍ASP.NET Core 数据保护零碎:它是什么,为什么咱们须要它,以及它如何工作。 为什么咱们须要数据保护零碎?数据保护零碎是ASP.NET Core应用的一组加密api。加密必须由不受信赖的第三方解决的数据。 这方面的典型例子是身份验证cookie。cookie是在申请之间长久化状态的一种办法。你不心愿每次向服务器申请时都必须提供用户名和明码,这将十分麻烦! 相同,只需向服务器提供一次凭据。服务器验证你的详细信息,并收回一个cookie,表明“他不须要提供任何其余证实,置信他。”对于后续的申请,能够简略地提供该cookie,而不用提供凭据。浏览器主动发送cookie与后续申请,这是web为用户实现晦涩登录体验的形式。cookie是十分敏感的货色。任何蕴含cookie的申请都将被视为原始用户发送的申请,就像原始用户在每个申请中都提供了用户名和明码一样。浏览器中有很多保护措施(例如CORS)来阻止攻击者拜访这些cookie。 然而,这不仅仅是阻止他人失去你的cookie。作为一个网站所有者,你也不心愿用户篡改他们本人的cookie。 身份验证cookie通常不仅仅蕴含通过身份验证的用户的ID或名称。它们通常蕴含各种附加的要求。它蕴含了用户的详细信息。它们能够是实在数据,如名称、电子邮件或电话号码,但它们也能够是与权限相干的申明,如是否是管理员或是否能够编辑。 对于每个申请,通常都须要这些,以确定是否容许用户采取操作。通常蕴含在发送给用户的身份验证cookie中,而不是每次申请都必须从数据库加载。这使得应用程序更加容易——一旦通过从cookie中提取用户主体对用户进行身份验证,应用程序就会确切地晓得用户领有哪些权限。这意味着应用程序必须信赖cookie。如果cookie是明文发送的,那么用户只需编辑这些值,就会裸露应用程序中显著的安全漏洞。 ASP.NET Core数据保护零碎正是为了这个目标而应用的。它对敏感数据(如身份验证cookie)进行加密和解密。通过在响应中返回身份验证cookie之前对其进行加密,应用程序晓得该cookie没有被篡改,并能够信赖其值。 数据保护零碎如何工作?数据保护零碎试图解决一个辣手的问题:如何爱护裸露给攻击者的敏感数据,现实状况下不向开发人员裸露任何密钥,同时遵循加密的最佳实际。 数据保护零碎应用对称密钥加密来爱护数据。应用蕴含随机数据的密钥加密数据,应用雷同的密钥解密数据。 在一个典型的ASP.NET Core应用程序可能有几种不同类型的不相干数据须要加密。例如,除了身份验证cookie之外,可能还须要加密跨站点申请伪造令牌(CSRF)或明码重置令牌。 你能够将雷同的键用于所有这些不同的目标,但这可能会带来问题。例如,如果明码重置令牌不能“意外地”(更有可能是歹意地)用作身份验证令牌,那就好得多。 ASP.NET Core数据保护零碎实现了这一指标。数据保护零碎有一个不能间接应用的父密钥。必须从父密钥派生子密钥,这些子密钥用于加密和解密数据。 应用雷同的purpose字符串从父密钥派生密钥总是会给出雷同的密钥,因而如果你领有父密钥并且晓得purpose字符串,那么总是能够解密已加密的数据。如果密钥是用不同的purpose导出的,那么尝试解密数据将会失败。这样能够保持数据隔离,这对安全性更好。 在大多数状况下,你不用间接与数据保护零碎交互来创立密钥或加密数据。这是由ASP.NET Core外围框架及其附带的库解决的。它们确保在你的应用程序中为每个不同的purpose应用惟一的字符串。如果你违心,你能够创立本人的爱护程序并加密其余数据(见下文),但这不是ASP.NET Core的日常运行所必须的。 我是一个.net框架开发者——这听起来很像<machineKey>?数据保护零碎是ASP.NET Core的一个新性能。,然而爱护身份验证令牌的须要并不是新的,那么咱们以前用的是什么呢?答案是<machineKey>。<machineKey>元素的应用形式与ASP.NET Core数据保护零碎十分类似,配置密钥和密码学套件,用于通过身份验证零碎加密数据(以及其余中央)。可怜的是,应用这个密钥时有些简单,因为它通常是从__machine.config__读取的。必须在运行应用程序的机器上配置。在集群中运行时,必须确保这些键放弃同步,否则可能会产生问题! 在.net Framework 4.5中,咱们能够替换<machineKey>元素及其应用的整个加密管道。 如何治理数据保护密钥?如果对安全性有所理解,那么你可能曾经听到应该定期轮换明码、秘密和证书的说法。如果你的某个机密被泄露了,这能够在肯定水平上缩小影响。这就是为什么签发HTTPS证书的寿命越来越短的起因。 依据你从框架和工具取得的反对,更换秘钥和证书可能会很苦楚,特地是在过渡时期,可能须要同时反对新旧秘钥。 鉴于数据保护对于爱护ASP.NET Core是至关重要的。你不会诧异秘钥轮换是数据保护零碎的默认设置。默认状况下,数据保护的生命周期为90天,但通常不用为此放心。当旧密钥快要过期时,数据保护零碎会主动创立新的密钥。所有可用密钥的汇合称为密匙环。 在这篇文章中,我不会深刻密钥治理的细节。请留神,秘钥轮换是主动产生的,只有你不删除任何旧的键(或显式地撤销它们),那么加密的数据依然能够应用过期的键检索。过期的密钥不能用于加密新数据。 我是否也能够爱护其余数据,还是仅用于身份验证cookie?数据保护零碎由ASP.NET Core隐含地应用并解决认证令牌的加密和解密。它也被ASP.NET Core用来爱护明码重置和MFA令牌。你不须要为这种爱护做任何事件——框架本人解决爱护。 如果你有本人想要加密的长期数据,能够间接应用数据保护api。我将在前面的文章中具体介绍,但以下内容展现了中如何应用IDataProtectionProvider服务(默认在ASP.NET Core apps)加密和解密一些数据: public class MyClass{ // The IDataProtectionProvider is registered by default in ASP.NET Core readonly IDataProtectionProvider _rootProvider; public MyClass(IDataProtectionProvider rootProvider) { _rootProvider = rootProvider; } public void RunSample() { // Create a child key using the purpose string string purpose = "Contoso.MyClass.v1"; IDataProtector protector = provider.CreateProtector(purpose); // Get the data to protect Console.Write("Enter input: "); string input = Console.ReadLine(); // Enter input: Hello world! // protect the payload string protectedPayload = _protector.Protect(input); Console.WriteLine($"Protect returned: {protectedPayload}"); //PRINTS: Protect returned: CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ // unprotect the payload string unprotectedPayload = _protector.Unprotect(protectedPayload); Console.WriteLine($"Unprotect returned: {unprotectedPayload}"); //PRINTS: Unprotect returned: Hello world }}一般来说,这并不是你想要做的事件。我集体只在解决明码重置和相似的令牌时须要它。 ...

January 15, 2021 · 1 min · jiezi

关于c#:改进你的c代码的5个技巧三

本文齐全独立于前两篇文章。如果你喜爱它们,我心愿你也会喜爱这个。在上一篇文章中,我展现了哪种办法更快,并比拟了代码的执行速度。在本文中,我将展现不同代码片段的内存耗费状况。为了显示内存映射和调配图,我应用了CLR profiler 32位版本,和平常一样,我在Windows平台上应用了4GB RAM和Core i3 CPU。内存耗费或调配图可能依据零碎运行的过程而变动。因而,如果你失去一个不同的输入或行为的代码,那么请与咱们分享你的教训。 让咱们开始“改良c#代码的5个技巧:第3局部”的旅程。 StringBuilder耗费的内存比String少在我的上一篇文章中,我曾经展现了在长连贯操作的场景中字符串的速度有多慢。这里咱们会看到一个字符串和StringBuilder的内存调配图。让我来演示一下。上面是我应用字符串和StringBuilder进行雷同操作的代码。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; using System.Net; using System.Net.NetworkInformation; using System.Threading; using System.Globalization; using System.Data.SqlClient; namespace Test1 { public class Test1 { string Name ; public void Process() { Name = Name + "A"; } } public class Test2 { StringBuilder sb = new StringBuilder(); public void Process() { sb.Append("A"); } } class Program { static void Main(string[] args) { Test1 t = new Test1(); t.Process(); Test2 t1 = new Test2(); t1.Process(); } } } 这是代码执行时的内存调配图。这里咱们从main函数调用两个函数Process();只管它们都有雷同的名称,但它们属于不同的类和Test1.Process解决字符串数据,而Test2.Process()解决StringBuilder数据。在调配图中,咱们能够看到字符串处理函数耗费了Main()函数94%的资源,而Test2类中解决StringBuilder的Process()只耗费了Main()函数的0.21%的资源。 ...

January 14, 2021 · 2 min · jiezi

关于c#:NETC开发工具整理

——工欲善其事必先利其器 1、Visual Studio IDE微软出品的最弱小编译器,没有之一。官网下载地址:https://visualstudio.microsof... 2、JetBrains ReSharper一款Visual Studio IDE开发扩大插件,能够主动生成代码,智能剖析代码,标准开发代码。官网下载地址:https://marketplace.visualstu... 3、OzCode一款Visual Studio IDE开发扩大插件,调试神器。缩小了调试工夫并通过检测和隔离谬误,能够大大的进步工作的生产效率。 4、DevExpress一款第三方控件软件,控件比VS自带的更齐全,更好看。Winfrom、WPF和ASP.NET均可应用。 5、.NET Reflector一款由前微软员工开发的.net反编译软件,能够反编译查看所有.NET代码的源代码。 6、ILSpy一款开源的.Net程序集浏览器和反编译工具,能够反编译dll文件为C#或VB语言,和.NET Reflector比更轻量级。 7、ANTS Memory ProfilerSciTech.NET.Memory.Profiler两款软件内存应用状况剖析软件,不便排查内存透露等软件问题,并优化内存应用。针对C#、VB.Net、或其它.Net程序。 8、Fiddler一款通过代理的抓包软件,能够抓取winFrom软件或者ASP.NET页面调用的http记录,同时能够断点批改入参和出参,便于调试。ps:开始Fiddler代理后,会导致拜访局部网址无奈平安拜访。敞开Fiddler即可恢复正常。批改入参断点:bpu http地址,如 bpu https://segmentfault.com/批改入参断点:bpafter http地址 bpafter https://segmentfault.com/

January 14, 2021 · 1 min · jiezi

关于c++:组合Composite模式-in-C

组合模式,将对象组合成树形构造以示意“局部-整体”的层次结构,组合模式使得用户对单个对象和组合对象的应用具备一致性。ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ ——Erich Gamma et. al.伊始组合(Composite)模式,又叫作局部-整体模式,它是一种将对象组合成树状的层次结构的模式,用来示意“局部-整体”的关系,使用户对单个对象和组合对象具备统一的拜访性。 构造模型 ■ Component:形象的组件对象,为组合中的对象申明接口,让客户端能够通过这个接口来拜访和治理整个对象构造,能够在外面为定义的性能提供缺省的实现。■ Leaf:叶子节点对象,定义和实现叶子对象的行为,不再蕴含其余的子节点对象。■ Composite:组合对象,通常会存储子组件,定义蕴含子组件的那些组件的行为,并实现在组件接口中定义的与子组件无关的操作。■ Client:客户端,通过组件接口来操作组合构造外面的组件对象。 实现域Component定义struct Component { virtual ~Component(){} ABSTRACT(void process()); virtual void add(Component*) { return; } virtual void remove(Component*) { return; }};留神,下面ABSTRACT是一个C++封装宏,示意定义的办法是纯虚函数,亦即接口,原型如下: #define ABSTRACT(...) virtual __VA_ARGS__ = 0因为叶子对象没有add和remove办法的,这里在抽象类提供了一份默认实现。 叶子对象Leaf定义struct Leaf : Component { OVERRIDE(void process()) { /* do process self */ }};其中,下面OVERRIDE也是一个C++封装宏,示意实现或者覆写父类的接口(或办法),原型如下: #define OVERRIDE(...) virtual __VA_ARGS__ override组合对象Composite定义using Components = std::list<Component*>;struct Composite : Component { explicit Composite(const std::string& name) : name_{name} {} OVERRIDE(void process()) { /* do process self */ /* process child */ for (auto& c : components_) { c->process(); } } OVERRIDE(void add(Component* component)) { components_.push_back(component) } OVERRIDE(void remove(Component* component)) { components_.remove(component) }private: std::string name_; Components components_;};用户应用这里假如用户须要设计一个治理商品类别树的场景,如下 ...

January 13, 2021 · 1 min · jiezi

关于c:9回文数leetcode-C语言

题目如下:判断一个整数是否是回文数。回文数是斧正序(从左向右)和倒序(从右向左)读都是一样的整数。 思路一、先将数字转换为一个字符串,而后判断字符串是否是回文字符串。代码如下: /*** 判断一个整数是不是回文数***/#include <stdio.h>#include <string.h>#include <stdbool.h>#include <stdlib.h>// 将整数转换为数字字符串void myItoA(int num, char *str){ int i = 0; while (num > 0) { str[i++] = num % 10 + 48; num /= 10; } str[i] = '\0';}// 判断字符串是否是回文字符串// 双指针法,从首位开始遍历bool isPalindrome(int x){ if (x < 0) { return false; } if (x == 0) { return true; } // 获取数字长度 int len = 0; int temp = x; while (temp > 0) { len++; temp /= 10; } printf("len is %d\n", len); // 动态分配存储空间 char *str = (char *)malloc((len + 1) * sizeof(char)); myItoA(x, str); int k = 0; while (str[k] != '\0') { printf("%c", str[k++]); } for (int i = 0, j = len - 1; i < j; i++, j--) { if (str[i] != str[j]) { return false; } } return true;}int main (void) { int num = -12321; printf("\n%d\n", isPalindrome(num));} ...

January 13, 2021 · 2 min · jiezi

关于c:计算机如何表示整数

[TOC] 在计算机中,任何的数据都是用二进制: 0 和 1 来示意。整数也不例外。生存中的 10,在 8 个字节的整数中示意为 00001010。然而这样子只能示意负数和零。怎么示意正数呢?于是有了符号位的概念。在 8 个字节的整数中,最高位为符号位,0 代表负数,1 代表正数。所以 -10 就能够用 10001010 来示意。然而,间接采纳符号位会带来一系列问题: 00000000 和 10000000 示意为 0 和 -0 ,那么用那个来示意 0,还是都是零?加法问题。对于加法问题,试着运算 1 - 1 的值: 将 1 - 1 转换成 1 + (-1)转换成二进制:00000001 + 10000001运算后果为 10000010 转换成十进制为 -2很显著,这个后果不对。为了解决这个问题,在计算机中引入补码(2's complement)来解决。要解释为什么要应用补码,还得从无符号整型开始说起。 为了便于了解和不便,我用 3 个字节的整数来解说。但因为 C 语言最小都是 8 个字节,在代码验证方面应用 8 个字节。无符号整型(unsigned integer)3 个字节的无符号整型中,能够示意 2^3^ = 8 个数: 000 = 2^2 * 0 + 2^1 * 0 + 2^0 * 0 = 0+0+0 = 0001 = 2^2 * 0 + 2^1 * 0 + 2^0 * 1 = 0+0+1 = 1010 = 2^2 * 0 + 2^1 * 1 + 2^0 * 0 = 0+2+0 = 2011 = 2^2 * 0 + 2^1 * 1 + 2^0 * 1 = 0+2+1 = 3100 = 2^2 * 1 + 2^1 * 0 + 2^0 * 0 = 4+0+0 = 4101 = 2^2 * 1 + 2^1 * 0 + 2^0 * 1 = 4+0+1 = 5110 = 2^2 * 1 + 2^1 * 1 + 2^0 * 0 = 4+2+0 = 6111 = 2^2 * 1 + 2^1 * 1 + 2^0 * 1 = 4+2+1 = 7既然是整数,免不了要加减乘除。 ...

January 13, 2021 · 6 min · jiezi

关于c:Golang源码分析Golang如何实现自举-dist介绍二

前言  依据《Golang如何实现自举(一)》的相干疏导,晓得了go1.3的go编译是须要go_bootstrap、然而生成go_bootstrap,须要dist工具进行生成。那么本期次要关注dist工具。 1.dist工具介绍  其实dist工具是属于go的一个疏导工具,它负责构建C程序(如Go编译器)和go工具的初始疏导正本。它也能够作为一个无所不包用shell脚本替换以前实现的零工。通过“go tool dist”命令能够操作该工具。该工具不同零碎下对应在pkg/tool/下的目录中。<center>图1-1-1 dist工具介绍</center>  那么来看一下dist工作都有哪些操作,如图1-1-1。能够看出dist工作有6个操作,别离为打印装置信息,编译go_boostrap,清理编译文件,查看go env,装置拷贝go工具,查看go版本, 这几个操作。   通过对《【Golang源码剖析】Golang如何实现自举(一)》的理解,晓得dist是C源码所写。linux下是通过make.bash中gcc编译进去的,命令如下: #gcc -O2 -Wall -Werror -ggdb -o cmd/dist/dist -Icmd/dist '-DGOROOT_FINAL="/mnt"' cmd/dist/buf.c cmd/dist/build.c cmd/dist/buildgc.c cmd/dist/buildruntime.c cmd/dist/goc2c.c cmd/dist/main.c cmd/dist/unix.c cmd/dist/windows.c2.dist文件介绍  所有学习的本源都是先看看官网文档怎么说,而后学习能力强的能够在看看源码,加深对学习对了解。看dist目录前,先在看看它对应的文档:https://github.com/golang/go/...   文档中说:Dist自身是用非常简单的C编写的。所有与C库的交互,甚至规范的C库也被限度在单个零碎特定的文件中(plan9.c,unix.c,windows.c),以进步可移植性。须要的性能其余文件应通过可移植性层公开。职能在可移植层中以x前缀结尾,否则应用与现有性能雷同的名称,或与现有性能混同。例如,xprintf是可移植的printf。   到目前为止,dist中最常见的数据类型是字符串和字符串。然而,dist应用了两个命名为而不是应用char和char *数据结构Buf和Vec,它们领有它们指向的所有数据。Buf操作是以b结尾的函数;Vec操作是以v结尾的函数。任何函数申明的根本模式堆栈上的Buf或Vecs应该是 void myfunc(void){ Buf b1, b2; Vec v1; binit(&b1); binit(&b2); vinit(&v1); ... main code ... bprintf(&b1, "hello, world"); vadd(&v1, bstr(&b1)); // v1 takes a copy of its argument bprintf(&b2, "another string"); vadd(&v1, bstr(&b2)); // v1 now has two strings bfree(&b1); bfree(&b2); vfree(&v1);}binit / vinit调用筹备要应用的缓冲区或向量,从而初始化 数据结构以及bfree / vfree调用开释它们仍在的任何内存保持。应用这个习惯用法能够给咱们提供词法范畴的调配。 ...

January 11, 2021 · 2 min · jiezi

关于c:signal-信号处理测试

最近再看unix编程的书籍,理解下操作系统。对于sinal信号的毛病的形容有一些似懂非懂的中央,就依照例子做一个试验,看看零碎如何解决。代码如下: #include <stdio.h>#include <signal.h>#include <unistd.h>#include <string.h>#define INPUTLEN 100void inthandler(int s){ printf("received a signal %d\n",s); sleep(2); printf("leaving inthandler\n");}void quithandler(int s){ printf("received a signal %d\n",s); sleep(3); printf("leaving quithandler\n");}int main(int ac,char *av[]){ char input[INPUTLEN]; int nchars; signal(SIGINT,inthandler); signal(SIGQUIT,quithandler); do{ printf("\n type a message\n"); nchars=read(0,input,(INPUTLEN-1)); if(nchars==-1) perror("read return an error"); else{ input[nchars]='\0'; printf("you typed ,%s",input); } }while(strncmp(input,"quit",4)!=0);}测试场景(在centos7 零碎下测试): 间断屡次中断信号 通过上图的演示,在收回第一个中断信号后,捕捉信号处理。在屡次收回终端信号后,信号被阻塞,信号处理程序处理实现后,梗塞的雷同的信号被捕捉一次。2.距离发送中断信号和QUIT信号 发送一个中断信号后,零碎捕捉信号处理。在收回一个QUIT信号后,从中断信号处理的函数跳转导QUIT信号处理函数解决。3、被中断的零碎调用 当输出“hello” 后产生了中断,中断实现后输出“world n",最初只打印出 "world".看来在centos,并不是在read 时产生中断返回-1.

January 11, 2021 · 1 min · jiezi

关于c:8字符串转换整数LeetCodeC语言

/*** 将字符串转换为数字——LeetCode第8题** author: aliao*/#include <stdio.h>#include <limits.h>int myAtoi(char *str){ int i = 0; int start = 0; int len = 0; // 遍历字符串中起始的空格字符 while (str[i] == 32) { i++; } // 如果非空首字符不是-+或者0-9这三类字符,则间接返回0 // 如果是空字符串或者字符串只蕴含空白子字符 if (str[i] != '-' && str[i] != '+' && (str[i] < 48 || str[i] > 57)) { return 0; } else { start = i; len += 1; i++; } while (str[i] != '\0') { if (str[i] >= 48 && str[i] <= 57) { len += 1; i++; } else { break; } } int reverse = 0; int k = 10; int isNeg = 0; for (int j = 0; j < len; j++) { if (j == 0) { if (str[start + j] == '-') { isNeg = 1; continue; } else if (str[start + j] == '+') { continue; } } if (isNeg) { if (reverse < INT_MIN / 10 || reverse == INT_MIN / 10 && str[start + j] - 48 > 8) { return INT_MIN; } else { reverse = reverse * k - (str[start + j] - 48); } } else { if (reverse > INT_MAX / 10 || reverse == INT_MAX / 10 && str[start + j] - 48 > 7) { return INT_MAX; } else { reverse = reverse * k + (str[start + j] - 48); } } } return reverse;}int main (void) { char *str = "-2147483648"; printf("final value: %d", myAtoi(str));}执行用时:0 ms, 在所有 C 提交中击败了100.00%的用户内存耗费:5.8 MB, 在所有 C 提交中击败了6.09%的用户工夫复杂度O(n),空间复杂度O(1)

January 11, 2021 · 2 min · jiezi

关于c:8字符串转换整数LeetCodeC语言

/*** 将字符串转换为数字——LeetCode第8题** author: aliao*/#include <stdio.h>#include <limits.h>int myAtoi(char *str){ int i = 0; int start = 0; int len = 0; // 遍历字符串中起始的空格字符 while (str[i] == 32) { i++; } // 如果非空首字符不是-+或者0-9这三类字符,则间接返回0 // 如果是空字符串或者字符串只蕴含空白子字符 if (str[i] != '-' && str[i] != '+' && (str[i] < 48 || str[i] > 57)) { return 0; } else { start = i; len += 1; i++; } while (str[i] != '\0') { if (str[i] >= 48 && str[i] <= 57) { len += 1; i++; } else { break; } } int reverse = 0; int k = 10; int isNeg = 0; for (int j = 0; j < len; j++) { if (j == 0) { if (str[start + j] == '-') { isNeg = 1; continue; } else if (str[start + j] == '+') { continue; } } if (isNeg) { if (reverse < INT_MIN / 10 || reverse == INT_MIN / 10 && str[start + j] - 48 > 8) { return INT_MIN; } else { reverse = reverse * k - (str[start + j] - 48); } } else { if (reverse > INT_MAX / 10 || reverse == INT_MAX / 10 && str[start + j] - 48 > 7) { return INT_MAX; } else { reverse = reverse * k + (str[start + j] - 48); } } } return reverse;}int main (void) { char *str = "-2147483648"; printf("final value: %d", myAtoi(str));}执行用时:0 ms, 在所有 C 提交中击败了100.00%的用户内存耗费:5.8 MB, 在所有 C 提交中击败了6.09%的用户工夫复杂度O(n),空间复杂度O(1)

January 11, 2021 · 2 min · jiezi

关于c#:在NET-Core中使用Channel三

到目前为止,咱们始终在应用所谓的“Unbounded”通道。你会留神到,当咱们创立通道时,咱们这样做: var myChannel = Channel.CreateUnbounded<int>();但实际上,咱们能够这样做: var myChannel = Channel.CreateBounded<int>(1000);这与创立容量无限的列表或数组等其余汇合类型并无太大差异。在咱们的示例中,咱们创立了一个最多包容1000项的Channel。但为什么要限度本人呢?这就是背压的作用。 什么是背压?背压(特地是当波及消息传递/排队时)是指资源(无论是内存、ram、网络)是无限的。咱们应该可能在链条上施加“压力”,试着加重一些压力。至多,让生态系统中的其他人晓得咱们负荷过重,咱们可能须要一些工夫来解决他们的申请。 一般来说,当咱们探讨队列的背压时。简直所有状况下,咱们都在探讨一种办法,通知任何试图在队列中增加更多条目标人,要么他们根本无法再退出任何条目,要么他们须要推后一段时间。更常见的是,咱们探讨的队列是在达到肯定容量时纯正抛弃音讯。这种状况很少产生,然而咱们有这个选项。 那么它是如何与.net Channel一起工作的呢? Channel中的背压当应用通道时,咱们实际上有一个非常简单的办法来减少背压。代码看起来是这样的: var channelOptions = new BoundedChannelOptions(5){ FullMode = BoundedChannelFullMode.Wait};var myChannel = Channel.CreateBounded<int>(channelOptions);咱们能够指定以下残缺模式: 期待 在关上WriteAsync()调用之前,只需让调用者期待。 DropNewest / DropOldest 能够在Channel中拖放最老的或最新的我的项目,为咱们想要增加的项腾出空间。 DropWrite 简略地转储咱们应该写的音讯。 还有另外两段代码须要留神。 你能够调用WaitToWriteAsync(): await myChannel.Writer.WaitToWriteAsync();这让咱们Channel成了有界。当Channel已满时,咱们能够简略地期待,直到有空间。这意味着,即便关上了DropWrite FullMode,咱们也能够通过简略地期待,直到有容量为止,来限度扔在高空上的音讯数量。 咱们应该留神的另一段代码是: var success = myChannel.Writer.TryWrite(i);这容许咱们尝试写入队列,并返回,无论胜利与否。须要留神的是,此办法不是异步的。要么写入信道要么不写入信道,这里没有"如果你再多等一会儿,兴许能够。”  欢送关注我的公众号,如果你有喜爱的外文技术文章,能够通过公众号留言举荐给我。

January 11, 2021 · 1 min · jiezi

关于c#:将WCF迁移到gRPC

应用protobuf-net.Grpc将WCF服务迁徙到gRPC非常简单。在这篇博文中,咱们将看看它到底有多简略。微软对于将WCF服务迁徙到gRPC的官网指南只提到了Gooogle.Protobuf形式,如果你有很多数据契约须要迁徙到.proto格局,这可能会很耗时。然而,通过应用protobuf-net.Grpc咱们可能重用旧的WCF数据契约和服务契约,而只须要做最小的代码更改。 迁徙数据契约和服务契约 在本节中,咱们将应用一个简略的申请响应的组合服务,它能够让你下载给定交易者的单个投资组合或所有投资组合。服务和数据契约的定义如下: [ServiceContract]public interface IPortfolioService{ [OperationContract] Task<Portfolio> Get(Guid traderId, int portfolioId); [OperationContract] Task<List<Portfolio>> GetAll(Guid traderId);}[DataContract]public class Portfolio{ [DataMember] public int Id { get; set; } [DataMember] public Guid TraderId { get; set; } [DataMember] public List<PortfolioItem> Items { get; set; }}[DataContract]public class PortfolioItem{ [DataMember] public int Id { get; set; } [DataMember] public int ShareId { get; set; } [DataMember] public int Holding { get; set; } [DataMember] public decimal Cost { get; set; }}在将数据契约和服务契约迁徙到gRPC之前,我倡议为契约创立一个新的类库。这些契约能够通过我的项目援用或包援用在服务器和客户端之间很容易地共享,这取决于你的WCF解决方案的构造。一旦咱们创立了类库,咱们将源文件进行复制并开始迁徙到gRPC。 ...

January 7, 2021 · 4 min · jiezi