-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
512 lines (300 loc) · 248 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>风酥糖</title>
<subtitle>fetasty</subtitle>
<link href="https://fetasty.github.io/atom.xml" rel="self"/>
<link href="https://fetasty.github.io/"/>
<updated>2024-02-26T03:30:17.855Z</updated>
<id>https://fetasty.github.io/</id>
<author>
<name>fetasty</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>scapy 简单使用</title>
<link href="https://fetasty.github.io/posts/fff1101d/"/>
<id>https://fetasty.github.io/posts/fff1101d/</id>
<published>2024-02-26T03:26:57.000Z</published>
<updated>2024-02-26T03:30:17.855Z</updated>
<content type="html"><![CDATA[<p>Scapy 是一个强大的数据包处理工具,可以轻松的按照层次构建网络包,比如这样</p><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">packet = Ether()/IP(dst=<span class="string">"192.168.0.1"</span>)/TCP(dport=<span class="number">80</span>)/<span class="string">b'data'</span></span><br></pre></td></tr></tbody></table></figure><span id="more"></span><p>可以轻松的获取某一层的内容</p><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> packet.haslayer(Ether):</span><br><span class="line"> packet.getlayer(Ether).show()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> packet.haslayer(Raw):</span><br><span class="line"> packet.getlayer(Raw).show()</span><br><span class="line"></span><br><span class="line">packet.original <span class="comment"># 包的原始二进制bytes</span></span><br><span class="line">packet.getlayer(TCP).original <span class="comment"># 获取包的TCP层的二进制bytes</span></span><br></pre></td></tr></tbody></table></figure><p>可以读取 wireshark 的捕获文件</p><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">packets = rdpcap(<span class="string">'wireshark_capture.pcap'</span>)</span><br><span class="line"><span class="keyword">for</span> packet <span class="keyword">in</span> packets:</span><br><span class="line"> <span class="comment"># pass</span></span><br><span class="line">packets[<span class="number">0</span>].payload.show()</span><br></pre></td></tr></tbody></table></figure><p>可以在第 2 层或者第 3 层发送数据包,分别使用 <code>sendp</code> 或者 <code>send</code></p><p>也可以使用 scapy 来重播 wireshark 捕获的包</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install scapy</span><br></pre></td></tr></tbody></table></figure><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> scapy.<span class="built_in">all</span> <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建TCP服务器</span></span><br><span class="line">server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">server_socket.bind((<span class="string">'192.168.10.225'</span>, <span class="number">8555</span>))</span><br><span class="line">server_socket.listen(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"服务器已启动,等待客户端连接..."</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 接受客户端连接</span></span><br><span class="line">client_socket, client_address = server_socket.accept()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"客户端已连接:"</span>, client_address)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 网口</span></span><br><span class="line">select_iface = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">'-'</span> * <span class="number">10</span>)</span><br><span class="line"><span class="keyword">for</span> inter <span class="keyword">in</span> conf.ifaces:</span><br><span class="line"> iface: NetworkInterface = conf.ifaces[inter]</span><br><span class="line"> <span class="built_in">print</span>(iface.name, iface.network_name)</span><br><span class="line"> <span class="keyword">if</span> iface.name == <span class="string">'环回测试'</span>:</span><br><span class="line"> select_iface = iface</span><br><span class="line"> <span class="built_in">print</span>(iface.ips)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'192.168.1.2'</span> <span class="keyword">in</span> iface.ips[<span class="number">4</span>]) <span class="comment"># 也可以以这个作为判断条件, 寻找正确的网口</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 读取pcap文件</span></span><br><span class="line">packets: PacketList = rdpcap(<span class="string">'225to121_targets.pcapng'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> packet <span class="keyword">in</span> packets:</span><br><span class="line"> p: Packet = packet</span><br><span class="line"> <span class="keyword">if</span> p.haslayer(Raw):</span><br><span class="line"> <span class="comment"># 重播数据包</span></span><br><span class="line"> raw_layer = p.getlayer(Raw)</span><br><span class="line"> sendp(raw_layer.original, inter=<span class="number">0.5</span>, socket=client_socket)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"send: <span class="subst">{raw_layer.original.<span class="built_in">hex</span>()}</span>"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 关闭连接</span></span><br><span class="line">client_socket.close()</span><br><span class="line">server_socket.close()</span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>Scapy 是一个强大的数据包处理工具,可以轻松的按照层次构建网络包,
比如这样</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">packet = Ether()/IP(dst=<span class="string">"192.168.0.1"</span>)/TCP(dport=<span class="number">80</span>)/<span class="string">b'data'</span></span><br></pre></td></tr></tbody></table></figure></summary>
<category term="计算机基础" scheme="https://fetasty.github.io/categories/computer-science/"/>
<category term="计算机基础" scheme="https://fetasty.github.io/tags/computer-science/"/>
<category term="网络" scheme="https://fetasty.github.io/tags/network/"/>
</entry>
<entry>
<title>Wireshark 使用说明</title>
<link href="https://fetasty.github.io/posts/8eb85eb3/"/>
<id>https://fetasty.github.io/posts/8eb85eb3/</id>
<published>2024-02-26T03:08:52.000Z</published>
<updated>2024-02-26T03:13:30.511Z</updated>
<content type="html"><![CDATA[<h2 id="理解网络层次">理解网络层次</h2><p>OSI 五层协议</p><ul><li><p>物理层:一般是基于电信号进行 bit 流传输</p></li><li><p><strong>数据链路层</strong>: 定义 bit 信号分组方式,常见的协议是以太网协议 (Ethernet)</p><p>Ethernet 数据帧 [帧头,数据,帧尾]</p></li><li><p><strong> 网络层</strong>: 划分广播域 / 子网,一般网络层都是 IP 协议</p><p>IP 数据帧 [报头,数据]</p></li><li><p><strong> 传输层</strong>: 建立端口到端口的通信,常见传输层协议有 TCP/UDP</p><p>TCP 基于连接,提供可靠传输,面向字节流,三次握手 / 四次挥手(创建 / 断开连接), 粘包 / 拆包,timewait, 报文头长,总体传输慢,窗口,拥塞控制</p><p>UDP 无连接,尽可能快,不可靠传输,面向报文,过长报文会被分片</p></li><li><p><strong>应用层</strong></p></li></ul><img data-src="/posts/8eb85eb3/network_layers.png" class=""><p></p><p>使用 Wireshark 分析数据包时,一般关注的是后面三层,每层的报文头中都包含了特定信息,在数据层存放更上层的数据</p><span id="more"></span><p></p><h2 id="实际报文分析">实际报文分析</h2><p>我们看一个实际的 TCP 报文</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">###[ Ethernet ]###</span><br><span class="line"> dst = e0:73:e7:6f:b0:1b</span><br><span class="line"> src = 00:20:22:01:05:b6</span><br><span class="line"> type = IPv4</span><br><span class="line">###[ IP ]###</span><br><span class="line"> version = 4</span><br><span class="line"> ihl = 5</span><br><span class="line"> tos = 0x0</span><br><span class="line"> len = 132</span><br><span class="line"> id = 48263</span><br><span class="line"> flags = DF</span><br><span class="line"> frag = 0</span><br><span class="line"> ttl = 128</span><br><span class="line"> proto = tcp</span><br><span class="line"> chksum = 0xa741</span><br><span class="line"> src = 192.168.10.225</span><br><span class="line"> dst = 192.168.10.121</span><br><span class="line"> \options \</span><br><span class="line">###[ TCP ]###</span><br><span class="line"> sport = 8555</span><br><span class="line"> dport = 50283</span><br><span class="line"> seq = 739877280</span><br><span class="line"> ack = 3545067859</span><br><span class="line"> dataofs = 5</span><br><span class="line"> reserved = 0</span><br><span class="line"> flags = PA</span><br><span class="line"> window = 40942</span><br><span class="line"> chksum = 0xd82f</span><br><span class="line"> urgptr = 0</span><br><span class="line"> options = []</span><br><span class="line">###[ Raw ]###</span><br><span class="line"> load = '\\xc9\x00\x00\x00\\xf9\x00\x00\x00\\xbc\x14\\xa8e\x02\x00\x00\x00H\x00\x00\x00\\x80\\xd85\\\x01\x00\x00\x00\\x80\\xd85\\\x01\x00\x00\x00\\x80\\x96\\x98\x00\\xef\x03\x00\x00\x00\x00\x00\x00\x00\\xa0Z@33333\\xf3b@\\xbc\x14\\xa8e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'</span><br></pre></td></tr></tbody></table></figure><ul><li><p>以太网层 (Ethernet) 中最重要的信息</p><ul><li>源 MAC 地址</li><li>目的 MAC 地址</li><li>上层协议类型</li></ul></li><li><p>网络层 (IP)</p><ul><li>源 IP 地址</li><li>目的 IP 地址</li><li>版本,长度,标志位,上层协议类型 等</li></ul></li><li><p>传输层 (TCP)</p><ul><li>源端口</li><li>目的端口</li><li>长度,标志位,序列号 / 应答号 等</li></ul></li><li><p>用户数据 (示例中的传输层数据不是像 HTTP 一样普通的传输层协议报文,可能是自定义的协议报文)</p></li></ul><p></p><h2 id="选择正确的网口">选择正确的网口</h2><p>使用 Wireshark 抓包,首先需要选择正确的网络接口,如果目的数据包的源 IP 或者目的 IP 在某个网络接口上,就选择该网络接口</p><p>一般来说,名称中包含 "以太网" 的接口是通过网线连接的网口;包含 "WLAN" 的是无线网络的网口</p><p>Windows 上可以使用 <code>ipconfig /all</code> 来查看网口信息,确定要使用的网口</p><p>或者鼠标指向对应的网口,在 Tooltip 中查看网口配置的 IP 信息</p><p></p><h2 id="网络包过滤">网络包过滤</h2><p>开始捕获后一般会发现一个网口上的报文数量非常庞大,不过滤根本看不清楚</p><p>此时我们就需要用到上述网络层次相关知识</p><ul><li><p>网络层过滤 (IP 协议信息过滤)</p><p>IP 协议包含了源 IP 地址和目的 IP 地址,这也是我们在 IP 层上一般需要过滤的内容</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">ip // 协议过滤, 非ip协议的报文过滤掉</span><br><span class="line">ip.src == 192.168.10.121 // 源地址过滤</span><br><span class="line">ip.dst == 192.168.10.225 // 目标地址过滤</span><br><span class="line">ip.addr == 192.168.10.66 // 源或者目的地址过滤</span><br><span class="line">ip.dst [not] in {192.168.10.121, 192.168.10.225} // (不)在某几个值中</span><br><span class="line">ip.version == 4 // ip协议过滤</span><br><span class="line">ip.len > 100 // 如果需要, ip协议的其它信息也可以用于过滤</span><br></pre></td></tr></tbody></table></figure></li><li><p>传输层过滤 (TCP/UDP 协议信息过滤)</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">tcp // 协议过滤, 非tcp协议报文过滤掉</span><br><span class="line">tcp or udp // 协议过滤, 仅保留tcp或者udp报文</span><br><span class="line">tcp.srcport == 8788 // tcp源端口过滤</span><br><span class="line">udp.dstport != 8888 // udp目的端口过滤</span><br><span class="line">udp.dstport not in {8888, 8889}</span><br><span class="line">udp.dstport >= 2000 and udp.dstport <= 9000</span><br><span class="line">udp.port == 12345 // 源或者目的端口过滤</span><br></pre></td></tr></tbody></table></figure></li><li><p>应用层 / 用户数据过滤 (可以根据数据帧的特性,快速过滤出特定协议的数据包)</p><p>数据内容过滤时,中括号<strong>第一个数字是字节起始位置,第二个数字是字节长度</strong></p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">data.data[4:2] == 0300 // tcp/udp负载数据部分第字节开始的两字节为0300的包</span><br><span class="line">tcp.segment_data[0:2] == 4d15</span><br><span class="line">tcp.payload[0:2] == 6f72 // tcp负载数据过滤</span><br><span class="line">udp.payload[0:4] == 6f726179 // udp负载数据过滤</span><br><span class="line">data.len > 0 // 负载数据长度过滤</span><br><span class="line">data.data[0:1] == 6f // tcp/udp负载数据过滤</span><br><span class="line">data.data == 6f:72:61:79 // 整端数据匹配, 十六进制数据可以按照字节用:分开</span><br><span class="line">http.request.method == GET</span><br><span class="line">dns.qry.name == "www.baidu.com"</span><br><span class="line"></span><br><span class="line">http.request.uri contains "User" // contains 区分大小写</span><br><span class="line">http.host contains "baidu"</span><br><span class="line">http.request.uri matches "user" // matches 不区分大小写</span><br></pre></td></tr></tbody></table></figure></li></ul><p></p><h3 id="条件组合">条件组合</h3><p>以上的过滤条件都可以自由组合,使用 <code>and</code> <code>or</code><code>not</code>来连接多个判断条件</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">tcp.dstport in {12345, 12315} and http and ip.version == 6</span><br><span class="line">ip.addr == 192.168.31.2 and (udp.port == 12345 or tcp.port == 12345)</span><br></pre></td></tr></tbody></table></figure><p></p><h3 id="捕获数据导出">捕获数据导出</h3><ul><li>直接保存 (Save), 将保存指定时间内所有捕获的数据包,数据量一般非常大</li><li>导出特定分组 (Export Specified Packets), 可以选择只保存选中的包,或者已过滤的包 (Displayed), Range 参数可以选择保存第 xxx 包 - 第 yyy 包</li><li>导出分组解析结果 (Export Packet Dissections), 选择纯文本 (As PlainText), 可以过滤导出哪些包,同时可以在 Packet Format 中仅勾选 Packet Bytes,导出指定包的 hexdump</li></ul><p></p><p>一般来说为了便于分析,先初步过滤一下,比如 ip 过滤,然后将原始数据保存 (导出特定分组), 存储为<code>.pcapng</code></p><p>之后再使用 scapy 来进一步分析,重播,使用 scapy 重播可以取出特定层的原始数据,按照新的源 IP / 目标 IP 发送,或者发送到特定的 Socket</p><p></p><p></p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><h2 id="理解网络层次">理解网络层次</h2>
<p>OSI 五层协议</p>
<ul>
<li><p>物理层:一般是基于电信号进行 bit 流传输</p></li>
<li><p><strong>数据链路层</strong>: 定义 bit 信号分组方式,常见的协议是
以太网协议 (Ethernet)</p>
<p>Ethernet 数据帧 [帧头,数据,帧尾]</p></li>
<li><p><strong> 网络层</strong>: 划分广播域 / 子网,
一般网络层都是 IP 协议</p>
<p>IP 数据帧 [报头,数据]</p></li>
<li><p><strong> 传输层</strong>: 建立端口到端口的通信,
常见传输层协议有 TCP/UDP</p>
<p>TCP 基于连接,提供可靠传输,面向字节流,三次握手 / 四次挥手
(创建 / 断开连接), 粘包 / 拆包,timewait, 报文头长,总体传输慢,窗口,
拥塞控制</p>
<p>UDP 无连接,尽可能快,不可靠传输,面向报文,过长报文会被分片</p></li>
<li><p><strong>应用层</strong></p></li>
</ul>
<img data-src="/posts/8eb85eb3/network_layers.png" class="">
<p></p>
<p>使用 Wireshark 分析数据包时,一般关注的是后面三层,
每层的报文头中都包含了特定信息,在数据层存放更上层的数据</p></summary>
<category term="计算机基础" scheme="https://fetasty.github.io/categories/computer-science/"/>
<category term="计算机基础" scheme="https://fetasty.github.io/tags/computer-science/"/>
</entry>
<entry>
<title>函数调用约定</title>
<link href="https://fetasty.github.io/posts/377a3f70/"/>
<id>https://fetasty.github.io/posts/377a3f70/</id>
<published>2024-02-18T06:50:51.000Z</published>
<updated>2024-02-18T06:51:53.003Z</updated>
<content type="html"><![CDATA[<h2 id="函数调用约定分类">函数调用约定分类</h2><p>函数调用约定(CallingConvention)是规定函数在栈上的参数传递和清理方式的约定。不同的编程语言和编译器可能使用不同的调用约定,主要有以下几种常见的函数调用约定:</p><span id="more"></span><ol type="1"><li><p><strong>StdCall(标准调用约定)</strong> :</p><ul><li>参数由调用者在栈上<strong>顺序压入</strong>,由<strong>被调用函数负责清理栈</strong>。</li><li><strong>函数名称在链接时由名称修饰器(namedecoration)进行修饰,用于指定函数的参数数量和类型</strong>。可以支持函数重载</li><li> Windows API 中的大部分函数使用标准调用约定。</li></ul></li><li><p><strong>Cdecl(C 调用约定)</strong> :</p><ul><li>参数由调用者在栈上<strong>顺序压入</strong>,由<strong>调用者负责清理栈</strong>。</li><li><strong>函数名称在链接时不进行修饰</strong>。不支持函数重载</li><li>在 C 和 C++ 中常用的默认调用约定。</li></ul></li><li><p><strong>FastCall(快速调用约定)</strong> :</p><ul><li>将一些参数(通常是寄存器数量限制内的参数)存放在寄存器中传递,剩余的参数由调用者在栈上压入。</li><li>寄存器用于存储参数的寄存器数量和顺序由编译器约定。</li><li>函数名称在链接时不进行修饰。</li><li>可以提高函数调用的性能。</li></ul></li><li><p><strong>ThisCall(成员函数调用约定)</strong> :</p><ul><li>参数由调用者在栈上顺序压入,但第一个参数(this 指针)通过寄存器传递。</li><li>其余参数由调用者负责清理栈。</li><li>常用于非静态成员函数,this 指针通过 ECX 寄存器传递。</li></ul></li><li><p><strong>Winapi(Windows API 调用约定)</strong> :</p><ul><li>与 StdCall 相同,参数由调用者在栈上顺序压入,由被调用函数负责清理栈。</li><li>函数名称在链接时不进行修饰。</li><li>在 Windows API 中,Winapi 通常是 StdCall 的同义词。</li></ul></li><li><p><strong>Pascal(帕斯卡调用约定)</strong> :</p><ul><li>参数由调用者在栈上逆序压入,由被调用函数负责清理栈。</li><li>函数名称在链接时不进行修饰。</li><li>常用于 Delphi 等编程语言。</li></ul></li></ol><p>选择适当的函数调用约定主要取决于编程语言、平台和编译器的要求。通常情况下,你无需显式指定函数的调用约定,编译器会根据语言和平台的规范自动选择合适的调用约定。但在某些情况下,例如与非托管代码交互或使用特定的编译器选项时,可能需要手动指定函数的调用约定。</p><p>顺序压入(Arguments Pushed in Order)和逆序压入(Arguments Pushed inReverse Order)是函数调用过程中参数在栈上的压入顺序。</p><ol type="1"><li><strong>顺序压入</strong>:在顺序压入的调用约定中,函数参数按照从左到右的顺序依次压入栈中。也就是说,第一个参数被压入栈的位置最低,最后一个参数被压入栈的位置最高。这意味着栈的顶部是最后一个参数的位置。例如,假设有一个函数<code>void MyFunction(int a, int b, int c)</code>,使用顺序压入的调用约定时,参数<code>a</code> 会被首先压入栈,然后是参数 <code>b</code>,最后是参数<code>c</code>。在函数内部,通过访问栈上的相对偏移量,可以获取到相应的参数值。</li><li><strong>逆序压入</strong>:在逆序压入的调用约定中,函数参数按照从右到左的顺序依次压入栈中。也就是说,第一个参数被压入栈的位置最高,最后一个参数被压入栈的位置最低。这意味着栈的顶部是第一个参数的位置。例如,假设有一个函数<code>void MyFunction(int a, int b, int c)</code>,使用逆序压入的调用约定时,参数<code>c</code> 会被首先压入栈,然后是参数 <code>b</code>,最后是参数<code>a</code>。在函数内部,通过访问栈上的相对偏移量,可以获取到相应的参数值。</li></ol><p>顺序压入和逆序压入是两种不同的参数传递方式,而具体使用哪种方式取决于函数调用约定的规定。不同的编程语言、平台和编译器可能使用不同的参数压入顺序。因此,在编写和调用函数时,需要了解所使用的编程语言和调用约定的规范,以正确地传递参数。</p><h2 id="在c中指定函数的调用约定">在 C++ 中指定函数的调用约定</h2><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">__cdecl <span class="type">void</span> <span class="title">MyFunction</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span>;</span><br><span class="line"><span class="function">__stdcall <span class="type">void</span> <span class="title">MyFunction</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span>;</span><br><span class="line"><span class="function">__fastcall <span class="type">void</span> <span class="title">MyFunction</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span>;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">__thiscall <span class="type">void</span> <span class="title">MyMethod</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span>;</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure><p>在 C++源码中,可以使用一些特定的关键字和修饰符来表示一个函数是导出函数。具体的表示方式取决于所使用的编译器和平台。</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> _WIN32</span></span><br><span class="line"> <span class="meta">#<span class="keyword">define</span> DLL_EXPORT __declspec(dllexport) <span class="comment">// Microsoft Visual C++ 编译器的扩展,用于指定一个函数是导出函数</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DLL_IMPORT __declspec(dllimport)</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"> <span class="meta">#<span class="keyword">define</span> DLL_EXPORT</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DLL_IMPORT</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">DLL_EXPORT <span class="type">void</span> <span class="title">MyExportedFunction</span><span class="params">()</span></span>;</span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><h2 id="函数调用约定分类">函数调用约定分类</h2>
<p>函数调用约定(Calling
Convention)是规定函数在栈上的参数传递和清理方式的约定。不同的编程语言和编译器可能使用不同的调用约定,主要有以下几种常见的函数调用约定:</p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>extern C 用法</title>
<link href="https://fetasty.github.io/posts/73245494/"/>
<id>https://fetasty.github.io/posts/73245494/</id>
<published>2024-02-18T06:27:34.000Z</published>
<updated>2024-02-18T06:46:56.545Z</updated>
<content type="html"><![CDATA[<h2 id="extern-c-作用">extern C 作用</h2><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> {</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="comment">// 函数声明</span></span><br><span class="line"> <span class="comment">// 或者函数定义</span></span><br><span class="line"> <span class="comment">// 或者#include <C语言Header.h></span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></tbody></table></figure><p><code>extern "C"</code><strong>修饰的变量和函数按照 C 语言方式编译和连接</strong></p><span id="more"></span><p>Cpp 和 C 编译的编译方式是不同的,比如对于相同的函数原型:<code>void foo(int x, int y)</code></p><p>C 语言中该函数被编译后在符号库中的名字是<code>_foo</code></p><p>Cpp 中,函数被编译器编译后,在符号库中的名字会带上参数类型,会产生像<code>_foo_int_int</code>(不同编译器可能生成的名字不同,但都使用相同机制) 之类的名字</p><p>Cpp <strong>也是依靠这种机制实现函数重载的</strong></p><p><code>extern "C"</code> 的作用就是指示编译器,将其修饰或包含的代码按照 C 语言方式编译,编译后的函数符号不包含参数类型,<strong>也正是因为这个,</strong><code>extern "C"</code><strong>中包含的代码不能包含重载函数</strong></p><h2 id="c与cpp中的使用">C 与 Cpp 中的使用</h2><h3 id="c语言中调用cpp代码">C 语言中调用 Cpp 代码</h3><p>当 Cpp 导出 C 语言格式的函数后,不仅 C 语言可以调用 Cpp 的函数;Cpp 编写的函数库 (lib/dll/a/so), 也可以以 C 语言函数接口为标准,提供给其它语言使用,比如 Python, C# 或者 Lua 等,以此实现多语言之间的混合使用 Cpp 头文件</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// cpph.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> CPPH_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CPPH_H</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 只在C++中让extern "C"出现, C语言不支持该语法</span></span><br><span class="line"><span class="comment">// 用__cplusplus宏判断后, C++和C中可以共用这份头文件</span></span><br><span class="line"><span class="comment">// 即使编译为运行库, 也需要一份可以共用的接口头文件</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> {</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span></span>;</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></tbody></table></figure><p>Cpp 实现源码 (或者实现的函数库 lib/dll)</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// cpph.cc</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"cpph.h"</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> x + y;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>C 语言文件</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// c_file.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">extern</span> <span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span></span>; <span class="comment">// 或者#include "cpph.h", 包含Cpp头文件</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> result = <span class="built_in">add</span>(<span class="number">3</span>, <span class="number">5</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, result);</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="cpp中调用c代码">Cpp 中调用 C 代码</h3><p>C 头文件</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// chead.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> CHEAD_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CHEAD_H</span></span><br><span class="line"><span class="function"><span class="keyword">extern</span> <span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span></span>;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></tbody></table></figure><p>C 源文件</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// chead.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"chead.h"</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> x + y;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Cpp 中调用</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="comment">// 或者 extern "C" int add(int x, int y);</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> {</span><br><span class="line"> <span class="meta">#<span class="keyword">include</span> <span class="string">"chead.h"</span></span></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> c = <span class="built_in">add</span>(<span class="number">100</span>, <span class="number">200</span>);</span><br><span class="line"> std::cout << c << std::endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><h2 id="extern-c-作用">extern C 作用</h2>
<figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> {</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="comment">// 函数声明</span></span><br><span class="line"> <span class="comment">// 或者函数定义</span></span><br><span class="line"> <span class="comment">// 或者#include &lt;C语言Header.h&gt;</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></tbody></table></figure>
<p><code>extern "C"</code><strong>修饰的变量和函数按照 C 语言方式编译和连接</strong></p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>位运算</title>
<link href="https://fetasty.github.io/posts/2633a26/"/>
<id>https://fetasty.github.io/posts/2633a26/</id>
<published>2024-01-17T02:06:12.000Z</published>
<updated>2024-01-17T10:23:28.661Z</updated>
<content type="html"><![CDATA[<p>位运算是计算机中最常用的操作之一,运用好位运算可以在特定情况下大幅提高计算效率</p><h2 id="原反补码">原反补码</h2><p>正数的原反补码都是自身 负数的补码为原码取反,符号位不变;补码为反码加 1, 符号位需要进位时丢弃进位符号位变 0 (进位溢出)计算机中的数字都是以补码表示</p><h2 id="有符号整型的二进制位">有符号整型的二进制位</h2><p>以 char (signed char, 1 字节) 为例</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0 = 0000 0000 b</span><br><span class="line">-1 = 1111 1111 b</span><br></pre></td></tr></tbody></table></figure><span id="more"></span><h2 id="移位操作">移位操作</h2><h3 id="左移">左移</h3><p>以 cpp 为例,左移操作是将数据的所有二进制位都向左移动一定位数,高位丢弃,低位补 0</p><p>左移 1 位相当于原数据乘以<span class="math inline"> \(2^1\)</span>,左移 n 位相当于原数据乘以<span class="math inline"> \(2^n\)</span>,高位丢弃相当于乘以<span class="math inline"> \(2^n\)</span> 后高位溢出</p><p></p><h3 id="右移">右移</h3><p>右移操作需要分情况</p><ol type="1"><li>有符号正数,符号位为 0, 右移低位丢弃,高位补 0</li><li> 有符号负数,符号位为 1, 右移低位丢弃,高位补 1</li><li> 无符号整数,右移低位丢弃,高位补 0</li></ol><p>右移 1 位相当于数字除以<span class="math inline"> \(2^1\)</span>,右移 n 位相当于除以<span class="math inline"> \(2^n\)</span>,低位丢弃的数字相当于整数除法的精度丢失</p><p></p><p>移位的操作效果相当于乘除<span class="math inline"> \(2^n\)</span>,但是移位的操作效率比乘除运算的效率更高</p><p>如果整数无法被<span class="math inline"> \(2^n\)</span> 整除,尾部的小数部分被丢弃,相当于结果减去了小数部分,所以右移可能结果会偏小(向下取整), 因此 -1 右移之后还是 -1, 二进制位不变</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">(<span class="number">-5</span>) >> <span class="number">1</span>; <span class="comment">// -3, 11111111 11111111 11111111 11111101</span></span><br><span class="line"><span class="number">5</span> >> <span class="number">1</span>; <span class="comment">// 2, 00000000 00000000 00000000 00000010</span></span><br><span class="line"><span class="number">-1</span>; <span class="comment">// 11111111 11111111 11111111 11111111</span></span><br><span class="line"><span class="number">-1</span> >> <span class="number">1</span>; <span class="comment">// -1, 11111111 11111111 11111111 11111111</span></span><br><span class="line"><span class="type">uint32_t</span> num = (<span class="type">uint32_t</span>)<span class="number">-1</span>; <span class="comment">// 4294967295, 11111111 11111111 11111111 11111111</span></span><br><span class="line">num >> <span class="number">1</span>; <span class="comment">// 2147483647, 01111111 11111111 11111111 11111111</span></span><br></pre></td></tr></tbody></table></figure><p></p><h2 id="读写数据的二进制位">读写数据的二进制位</h2><p>可以通过 "与" 和 "或" 操作来读写一个数据的对应位,虽然本文源码以 <code>C++</code>为例,但这在多数语言中都是相通的操作</p><p>使用 Python 时需要注意一下,Python 的整数是使用数组实现,其长度可以无限大,不像普通语言,整数类型具有固定或有限长度</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> test = <span class="number">123</span>; <span class="comment">// C++中的int一般为32位整型</span></span><br><span class="line"><span class="comment">// 读取所有的二进制位</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">31</span>; i >= <span class="number">0</span>; --i) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d"</span>, (test & (<span class="number">0x1</span> << i)) != <span class="number">0</span> ? <span class="number">1</span> : <span class="number">0</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 输出: 00000000000000000000000001111011</span></span><br><span class="line"><span class="comment">// 将倒数第2位设置为0</span></span><br><span class="line">test &= ~(<span class="number">0x1</span> << <span class="number">1</span>); <span class="comment">// 00000000000000000000000001111001</span></span><br><span class="line"><span class="comment">// 再将倒数第3位设置为1</span></span><br><span class="line">test |= (<span class="number">0x1</span> << <span class="number">2</span>); <span class="comment">// 00000000000000000000000001111101</span></span><br></pre></td></tr></tbody></table></figure><p>这样的话,我们可以将一个整型变量当作一个 bit 数组使用,对任意位进行读写</p><p>但是 int 只有 32 位长度,如果我们需要更大的 bit 数组怎么办呢,int64 吗?要是需要的长度远大于 64 呢?</p><p>我们可以使用整型数组来当作一个大的 bit 数组使用,而且数组的内存是连续的,非常容易操作</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 我们将一个长度为5的int数组当作160位的bit数组使用</span></span><br><span class="line"><span class="type">int</span> bit_arr[<span class="number">5</span>] = {<span class="number">0</span>};</span><br><span class="line"><span class="comment">// 将第100位(从左到右)设置为1</span></span><br><span class="line"><span class="type">int</span> int_index = <span class="number">100</span> / <span class="number">32</span>; <span class="comment">// 先取得bit对应的int下标</span></span><br><span class="line"><span class="type">int</span> bit_index = (<span class="number">100</span> % <span class="number">32</span>); <span class="comment">// 再取得bit在对应int中的下标</span></span><br><span class="line">bit_arr[int_index] |= (<span class="number">0x1</span> << (<span class="number">31</span> - bit_index)); <span class="comment">// int最左的1位需要左移31位才能访问</span></span><br><span class="line"><span class="comment">// 同理, 取得第100位的bit值也是一样的步骤, 先计算int下标, 再计算int内的bit下标</span></span><br><span class="line"><span class="type">int</span> bit_value = (bit_arr[int_index] & (<span class="number">0x1</span> << (<span class="number">31</span> - bit_index))) != <span class="number">0</span> ? <span class="number">1</span> : <span class="number">0</span>;</span><br></pre></td></tr></tbody></table></figure><p>可以再进一步,将上述计算封装起来,仅对外暴露简单易用的接口,很多语言的标准库中都封装好了,比如 cpp 中的 bitset,有兴趣可以自己封装试试</p><p></p><p></p><h2 id="数据转为二进制字符串">数据转为二进制字符串</h2><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T></span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">print_bin</span><span class="params">(T data)</span> </span>{</span><br><span class="line"> std::string str;</span><br><span class="line"> <span class="type">uint8_t</span>* bytes = (<span class="type">uint8_t</span>*)&data;</span><br><span class="line"> <span class="keyword">auto</span> len = <span class="built_in">sizeof</span>(T);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = len - <span class="number">1</span>; i >= <span class="number">0</span>; --i) {</span><br><span class="line"> <span class="type">uint8_t</span> v = bytes[i];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">8</span> - <span class="number">1</span>; j >= <span class="number">0</span>; --j) {</span><br><span class="line"> str.<span class="built_in">append</span>((v & (<span class="number">0x1</span> << j)) > <span class="number">0</span> ? <span class="string">"1"</span> : <span class="string">"0"</span>);</span><br><span class="line"> }</span><br><span class="line"> str.<span class="built_in">append</span>(<span class="string">" "</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>, str.<span class="built_in">c_str</span>());</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h2 id="数据按位取反之后得到的值是什么">数据按位取反之后得到的值是什么</h2><p>先利用上述的 <code>print_bin</code>看看 <code>6</code> <code>-6</code><code>~6</code>的二进制</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print_bin</span>(<span class="number">6</span>)</span><br><span class="line"><span class="built_in">print_bin</span>(<span class="number">-6</span>)</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ~<span class="number">6</span>)</span><br><span class="line"><span class="built_in">print_bin</span>(~<span class="number">6</span>)</span><br></pre></td></tr></tbody></table></figure><p>结果如下</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">11111111 11111111 11111111 11111010 // -6 的二进制(补码)</span><br><span class="line">00000000 00000000 00000000 00000110 // 6 的二进制(补码)</span><br><span class="line">-7</span><br><span class="line">11111111 11111111 11111111 11111001 // ~6 的二进制, 可以看到, 其真值为-7</span><br></pre></td></tr></tbody></table></figure><p><code>~6</code>为什么是 <code>-7</code>呢,其实我们将 <code>-7</code>的补码写出来就会发现,它与 <code>~6</code>的二进制完全一样</p><p>好像发现了点什么,我们再看看 <code>~(-6)</code></p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print_bin</span>(<span class="number">-6</span>)</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ~(<span class="number">-6</span>))</span><br><span class="line"><span class="built_in">print_bin</span>(~(<span class="number">-6</span>))</span><br></pre></td></tr></tbody></table></figure><p>结果如下</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">11111111 11111111 11111111 11111010 // -6的二进制 (-6的补码)</span><br><span class="line">5</span><br><span class="line">00000000 00000000 00000000 00000101 // ~(-6)的二进制 (5的补码)</span><br></pre></td></tr></tbody></table></figure><p><code>6</code>取反得到 <code>-7</code>,<code>-6</code>取反得到 <code>5</code>,难道对一个整数取反就是它的相反数减去 1?</p><p>我们多用几个数字测试一下,包含特殊值 0</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">-3</span>; i < <span class="number">4</span>; ++i)</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d %d\n"</span>, i, ~i + <span class="number">1</span>);</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>结果如下,0 也符合预期</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">-3 3</span><br><span class="line">-2 2</span><br><span class="line">-1 1</span><br><span class="line">0 0</span><br><span class="line">1 -1</span><br><span class="line">2 -2</span><br><span class="line">3 -3</span><br></pre></td></tr></tbody></table></figure><p>到此我们其实得到了一个普适的规律: <code>~n + 1 = -n</code>也就是<strong>对一个整数取反 (~) 并加 1 得到它的相反数</strong></p><h2 id="取得二进制位最右边的1">取得二进制位最右边的 1</h2><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> mostRightOne = n & (~n + <span class="number">1</span>);</span><br></pre></td></tr></tbody></table></figure><p>根据以上章节提到的结论 <code>~n + 1 = -n</code>可以得到以下等价代码</p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> mostRightOne = n & (-n);</span><br></pre></td></tr></tbody></table></figure><h2 id="使用异或交换两个数字">使用异或交换两个数字</h2><ul><li><p>任何数字异或自身等于 0 <code>a ^ a == 0</code></p></li><li><p>任何数字与 0 异或等于自身 <code>a ^ 0 == a</code></p></li><li><p>异或满足交换律和结合律<code>a ^ b == b ^ aa ^ (b ^ c) == (a ^ b) ^ c</code></p><figure class="highlight cpp"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">1</span>, b = <span class="number">2</span>;</span><br><span class="line">a = a ^ b;</span><br><span class="line">b = a ^ b;</span><br><span class="line">a = a ^ b:</span><br></pre></td></tr></tbody></table></figure></li></ul><p></p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>位运算是计算机中最常用的操作之一,
运用好位运算可以在特定情况下大幅提高计算效率</p>
<h2 id="原反补码">原反补码</h2>
<p>正数的原反补码都是自身 负数的补码为原码取反,符号位不变;
补码为反码加 1, 符号位需要进位时丢弃进位符号位变 0 (进位溢出)
计算机中的数字都是以补码表示</p>
<h2 id="有符号整型的二进制位">有符号整型的二进制位</h2>
<p>以 char (signed char, 1 字节) 为例</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0 = 0000 0000 b</span><br><span class="line">-1 = 1111 1111 b</span><br></pre></td></tr></tbody></table></figure></summary>
<category term="数据结构&设计模式" scheme="https://fetasty.github.io/categories/algorithm-and-design-pattern/"/>
<category term="数据结构&设计模式" scheme="https://fetasty.github.io/tags/algorithm-and-design-pattern/"/>
</entry>
<entry>
<title>ArchLinux 使用</title>
<link href="https://fetasty.github.io/posts/2d9deefc/"/>
<id>https://fetasty.github.io/posts/2d9deefc/</id>
<published>2023-12-09T02:53:22.000Z</published>
<updated>2023-12-11T06:46:34.275Z</updated>
<content type="html"><![CDATA[<p>Arch 是众多 Linux 发行版中的其中一个,但是它比较纯净,同时安装也相比于其它的 Linux 发行版复杂一些,从头安装一个 ArchLinux 可以学习不少 Linux 知识</p><p>推荐按照官方的安装教程一步步执行:https://wiki.archlinux.org/title/Installation_guide</p><p>最好阅读英文版,更新日期比较新</p><p>以下是折腾 Arch 的记录</p><span id="more"></span><h2 id="安装步骤">1 安装步骤</h2><h3 id="制作启动u盘">1.1 制作启动 U 盘</h3><ul><li>镜像文件下载: https://archlinux.org/download/</li><li> 使用 rufus 等工具制作 UEFI 启动盘</li><li> BIOS 中设置启动模式为 UEFI</li><li> 通过 U 盘启动</li></ul><h3 id="连接网络">1.2 连接网络</h3><p>U 盘启动后是一个用于安装系统的 Linux 环境,必须连接到网络才能进行 archlinux 的安装</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看网卡状态, 打开网口</span></span><br><span class="line">ip <span class="built_in">link</span></span><br><span class="line">ip <span class="built_in">link</span> <span class="built_in">set</span> dev [interface] up</span><br><span class="line"></span><br><span class="line"><span class="comment"># iwctl 连接wifi</span></span><br><span class="line">iwctl <span class="comment"># 进入iwc交互模式</span></span><br><span class="line">[iwd] <span class="built_in">help</span></span><br><span class="line">[iwd] device list</span><br><span class="line">[iwd] device [device] set-property Powered on</span><br><span class="line">[iwd] adapter [adapter] set-property Powered on</span><br><span class="line">[iwd] station [device] scan</span><br><span class="line">[iwd] station [device] get-networks</span><br><span class="line">[iwd] station [device] connect SSID</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检测网络</span></span><br><span class="line">ping archlinux.org</span><br></pre></td></tr></tbody></table></figure><p>如果 wifi 不好连接,可直接使用网线连接</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看系统ip地址</span></span><br><span class="line">ip addr</span><br></pre></td></tr></tbody></table></figure><p>之后使用 ssh 远程连接,方便操作</p><h3 id="同步系统时钟">1.3 同步系统时钟</h3><p>同步系统时钟</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 开启时间同步</span></span><br><span class="line">timedatectl set-ntp <span class="literal">true</span></span><br><span class="line"><span class="comment"># 时区不对先不用管</span></span><br><span class="line">timedatectl</span><br></pre></td></tr></tbody></table></figure><h3 id="磁盘分区">1.4 磁盘分区</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看磁盘设备</span></span><br><span class="line">lsblk</span><br><span class="line">fdisk -l</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用fdisk分区</span></span><br><span class="line">fdisk /dev/[nvme0n1] <span class="comment"># 需要分区的磁盘设备, 交互式操作, m查看帮助, 创建GTP分区表, 分区开始位置自动, 结束位置可以使用+1G的方式确定</span></span><br></pre></td></tr></tbody></table></figure><p>一般来说,一个 linux 系统需要以下 3 个分区</p><table><colgroup><col style="width: 12%"><col style="width: 30%"><col style="width: 57%"></colgroup><thead><tr class="header"><th>挂载点</th><th>大小</th><th>说明</th></tr></thead><tbody><tr class="odd"><td><code>/boot</code></td><td>300M ~ 1G</td><td>EFI 分区,一般需要是磁盘第一个分区</td></tr><tr class="even"><td><code>[swap]</code></td><td>4G ~ 32G (看心情)</td><td> 交换分区,内存不足时用于缓存</td></tr><tr class="odd"><td><code>/</code></td><td>剩余所有</td><td> linux 系统根目录</td></tr></tbody></table><p>也可以根据需要将 <code>/home</code>, <code>/root</code>,<code>/srv</code> 或者 <code>/var</code> 等进行单独分区,以便于数据备份</p><p>fdisk 分区写入后,退出交互操作,格式化各分区</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 格式化分区</span></span><br><span class="line">mkfs.ext4 /dev/[root_partition] <span class="comment"># 以及其它linux文件分区, /home, /root, /srv</span></span><br><span class="line">mkswap /dev/[swap_partition]</span><br><span class="line">mkfs.fat -F 32 /dev/[efi_system_partition] <span class="comment"># EFI分区必须格式化为FAT32格式</span></span><br></pre></td></tr></tbody></table></figure><h3 id="挂载系统分区">1.5 挂载系统分区</h3><p>所有的分区都要按照实际情况挂载上去,包括交换分区,之后的 <code>genfstab</code> 命令会检测所有的挂载分区和交换分区</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 首先挂载根分区</span></span><br><span class="line">mount /dev/[root_partition] /mnt</span><br><span class="line">mount --<span class="built_in">mkdir</span> /dev/[efi_system_partition] /mnt/boot</span><br><span class="line"><span class="comment"># 如果有自定义的其余分区, 也都挂载进来</span></span><br><span class="line">mount --<span class="built_in">mkdir</span> /dev/[home_partition] /mnt/home</span><br><span class="line">mount --<span class="built_in">mkdir</span> /dev/[root_home_partition] /mnt/root</span><br><span class="line">mount --<span class="built_in">mkdir</span> /dev/[srv_partition] /mnt/srv</span><br><span class="line"><span class="comment"># 如果有swap分区, 也打开它</span></span><br><span class="line">swapon /dev/[swap_partition]</span><br></pre></td></tr></tbody></table></figure><h3 id="更改pacman镜像源">1.6 更改 pacman 镜像源</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">nano /etc/pacman.d/mirrorlist</span><br><span class="line"><span class="comment"># 源的优先级取决于顺序, 可以将以下国内源添加在最上方</span></span><br><span class="line"><span class="comment"># Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch</span></span><br></pre></td></tr></tbody></table></figure><h3 id="安装系统">1.7 安装系统</h3><p>首先安装必须的基本包</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pacstrap -K /mnt base linux linux-firmware</span><br></pre></td></tr></tbody></table></figure><p>配置系统</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将分区挂载信息写入fstab文件, 生成文件后检查文件是否有错</span></span><br><span class="line">genfstab -U /mnt >> /mnt/etc/fstab</span><br></pre></td></tr></tbody></table></figure><p>change root 到新系统下</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">arch-chroot /mnt</span><br></pre></td></tr></tbody></table></figure><p>设置系统时间时区</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ln</span> -sf /usr/share/zoneinfo/[Asia/Shanghai] /etc/localtime</span><br><span class="line">hwclock --systohc <span class="comment"># 写入系统时间bios</span></span><br></pre></td></tr></tbody></table></figure><p>本地化配置</p><p>编辑 <code>/etc/locale.gen</code>, 取消注释<code>en_US.UTF-8 UTF-8</code>, 执行以下命名</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">locale-gen</span><br></pre></td></tr></tbody></table></figure><p>创建 <code>/etc/locale.conf</code>, 填入以下内容</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LANG=en_US.UTF-8</span><br></pre></td></tr></tbody></table></figure><p>设置网络名称</p><p>创建 <code>/etc/hostname</code> 文件,并填写自己的 <code>hostname</code></p><p>更改 root 账户密码</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">passwd</span><br></pre></td></tr></tbody></table></figure><p>安装配置 grub</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 更新源信息</span></span><br><span class="line">pacman -Sy</span><br><span class="line">pacman -S grub</span><br><span class="line"><span class="comment"># 安装启动文件</span></span><br><span class="line">grub-install --target=x86_64-efi --efi-directory=[/boot] --bootloader-id=GRUB</span><br><span class="line"><span class="comment"># 生成grub配置</span></span><br><span class="line">grub-mkconfig -o /boot/grub/grub.cfg</span><br></pre></td></tr></tbody></table></figure><p>安装 microcode 微码包</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># intel cpu安装intel-ucode, amd cpu安装amd-ucode</span></span><br><span class="line">pacman -S amd-ucode</span><br></pre></td></tr></tbody></table></figure><p>微码包应该尽量早的加载,可以通过 grub 配置</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 重新运行grub配置, 将自动检测微码包资源, 并放在最开始加载</span></span><br><span class="line">grub-mkconfig -o /boot/grub/grub.cfg</span><br><span class="line"><span class="comment"># 在/boot/grub/grub.cfg中应该能看到以下配置</span></span><br><span class="line"><span class="comment"># initrd /boot/[cpu_manufacturer]-ucode.img /boot/initramfs-linux.img</span></span><br></pre></td></tr></tbody></table></figure><p>安装基本软件</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装需要的软件</span></span><br><span class="line">pacman -S base-devel openssh nano dhcpcd wpa_supplicant neofetch dmidecode radeontop</span><br></pre></td></tr></tbody></table></figure><p>配置网络和 ssh (以免重启后未联网,还要重新操作,或者连接显示器,比较麻烦)</p><p>参考</p><p>https://wiki.archlinux.org/title/Network_configuration/Wireless</p><p>https://wiki.archlinux.org/title/Dhcpcd</p><p>https://wiki.archlinux.org/title/Wpa_supplicant</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 编辑ssh配置, 允许root登录</span></span><br><span class="line">nano /etc/ssh/sshd_config <span class="comment"># PermitRootLogin yes</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 打开ssh自启动</span></span><br><span class="line">systemctl <span class="built_in">enable</span> sshd</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加dhcp对wpa_supplicant(wifi wpa)的hook</span></span><br><span class="line"><span class="built_in">ln</span> -s /usr/share/dhcpcd/hooks/10-wpa_supplicant /usr/lib/dhcpcd/dhcpcd-hooks/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看网口</span></span><br><span class="line">ip <span class="built_in">link</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 仅开启无线网口的自启动配置, 如果没有@xxx, 那么会自启动所有网口</span></span><br><span class="line">systemctl <span class="built_in">enable</span> dhcpcd@[wlan0].service</span><br><span class="line"></span><br><span class="line"><span class="comment"># wpa_supplicant配置, wpa_supplicant会由dhcpcd自动打开, 如果使用systemctl自启动, 也可以开启wpa_supplicant@[wlan0].service</span></span><br><span class="line">wpa_passphrase [MYSSID] [passphrase] > /etc/wpa_supplicant/wpa_supplicant-[wlan0].conf</span><br></pre></td></tr></tbody></table></figure><p>配置好所有内容后,重启系统</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 关机使用poweroff</span></span><br><span class="line">reboot</span><br></pre></td></tr></tbody></table></figure><h2 id="使用pacman">2 使用 pacman</h2><p>帮助: <code>pacman -h</code></p><p>标签帮助: <code>pacman -Sh</code></p><p>更新软件源: <code>pacman -Sy</code></p><p>更新源并更新系统: <code>pacman -Syu</code></p><p>搜索在线包: <code>pacman -Ss <package_name></code></p><p>安装包: <code>pacman -S <package_name></code></p><p><code>pacman -Rns <package_name></code>删除软件以及不被其他软件依赖的包 (<code>-Rsu</code>可能删除其他软件包还在依赖的项,不安全)</p><p><code>pacman -Rc <package_name></code>删除软件包以及其配置项 (可以先使用</p><p><code>pacman -Qdtq</code> 列出不再被其它软件包依赖的软件包名称</p><h2 id="常用软件">3 常用软件</h2><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看cpu核心信息</span></span><br><span class="line">lscpu -e</span><br><span class="line"><span class="comment"># 查看各传感器温度</span></span><br><span class="line">pacman -Syu</span><br><span class="line">pacman -S lm_sensors <span class="comment"># 工具集, 可以搜索以下lm_sensors其余用法</span></span><br><span class="line">sensors <span class="comment"># 查看硬件温度</span></span><br><span class="line"><span class="comment"># 查看内存占用</span></span><br><span class="line">free -h</span><br><span class="line"><span class="comment"># 查看磁盘占用</span></span><br><span class="line"><span class="built_in">df</span> -h</span><br><span class="line"><span class="comment"># 查看系统信息</span></span><br><span class="line">pacman -S neofetch</span><br><span class="line">neofetch</span><br><span class="line"><span class="comment"># 查看磁盘分区详情</span></span><br><span class="line">lsblk</span><br><span class="line">fdisk -l</span><br><span class="line"><span class="comment"># 查看pci设备</span></span><br><span class="line">lspci [-k]</span><br><span class="line"><span class="comment"># 查看硬件信息</span></span><br><span class="line">dmidecode [-t memory]</span><br><span class="line"><span class="comment"># 查看amd显卡信息</span></span><br><span class="line">radeontop</span><br></pre></td></tr></tbody></table></figure><p>至此已安装完毕</p><h2 id="展示环节">4 展示环节</h2><img data-src="/posts/2d9deefc/sensors.png" class=""><img data-src="/posts/2d9deefc/cpu_ram.png" class=""><img data-src="/posts/2d9deefc/radeontop.png" class=""><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>Arch 是众多 Linux 发行版中的其中一个,但是它比较纯净,
同时安装也相比于其它的 Linux 发行版复杂一些,
从头安装一个 ArchLinux 可以学习不少 Linux 知识</p>
<p>推荐按照官方的安装教程一步步执行:
https://wiki.archlinux.org/title/Installation_guide</p>
<p>最好阅读英文版,更新日期比较新</p>
<p>以下是折腾 Arch 的记录</p></summary>
<category term="Linux" scheme="https://fetasty.github.io/categories/Linux/"/>
<category term="Linux" scheme="https://fetasty.github.io/tags/Linux/"/>
<category term="Arch" scheme="https://fetasty.github.io/tags/Arch/"/>
</entry>
<entry>
<title>Android 手机改造 Linux 服务器</title>
<link href="https://fetasty.github.io/posts/df321891/"/>
<id>https://fetasty.github.io/posts/df321891/</id>
<published>2023-12-08T13:50:30.000Z</published>
<updated>2023-12-11T06:46:34.258Z</updated>
<content type="html"><![CDATA[<p>手头上的旧手机为小米 6, 本文可能部分内容只在小米 6 上适用 [xiaomi 6sagit]</p><p>且本文主要讨论 LinuxDeploy (需要 root) 的方式,非 root 用户可使用 Termux 方式</p><span id="more"></span><h2 id="方案选择">1 方案选择</h2><p>前后测试了 3 种方法,最推荐使用 LinuxDeploy (chroot)</p><ul><li>Ubuntu touch 原生 Linux 系统,但是为了驱动手机设备,需要做很多工作,社区上适用于 xiaomi6 的 ubuntu touch 已经停止开发了,使用起来还有很多不足,<code>apt update && apt upgrade</code> 一下,可能设备就无法启动了</li><li> Termux (proot), Termux 本身的文件结构与 linux 系统不同,使用 proot 方式运行 linux, 性能有损耗 (但是并不多),对于非 root 用户该方式非常不错,而且可以通过 Termux-boot 插件实现自启动</li><li> LinuxDeploy (chroot), 需要 root 权限,初略了解,它应该比 proot 方式性能更好,原本的 Android 系统负责驱动设备硬件,维护设备运行,而 chroot 中的 linux 并行于 Android 系统运行,不必关心硬件设备的驱动</li></ul><p>使用 LinuxDeploy 的同时将系统刷为 lineageos, 使用原生安卓系统驱动设备,保证手机正常工作,同时尽量少的占用资源,不安装不开启不必要的应用,不过刷系统是个可选项,使用原生系统也问题不大</p><p>chroot (change root) 是一种非常原始的容器技术,仅仅是将一个进程的根目录更改到一个指定目录,限制访问和可见性,其余的硬件资源,网络资源等则还是和宿主系统共享,chroot 本身运行在内核态,需要 root 权限</p><p>小结:</p><ol type="1"><li>对于没有 Root 权限的 Android 设备,使用 Termux+proot 方式安装完整 linux 是最佳方案,proot 是用户空间的 chroot,系统调用会拦截一层,有一些性能损失,但是这种隔离远不如容器的隔离,性能损失比较小,是完全可以接受的 参考: <a href="https://wiki.termux.com/wiki/Main_Page">Termux Wiki</a></li><li> 对于有 Root 权限的 Android 设备,使用 LinuxDeploy (<a href="https://github.com/lateautumn233/Linuxdeploy-Pro">LinuxDeploy-Pro</a>原作者 meefik 的 github 库貌似已经没有更新,且安装时有一些问题),LinuxDeploy 使用 Chroot 实现,需要 Root 权限,相对于 Proot,其系统调用没有转换操作,性能更好,适合长期运行</li></ol><h2 id="前置准备">2 前置准备</h2><ol type="1"><li><p>bootloader 解锁</p></li><li><p>驱动安装,小米手机可以用 miflash 安装驱动</p></li><li><p>解决 Windows 上 usb3 使用 fastboot 时卡住的问题</p><p></p><figure class="highlight bat"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">@<span class="built_in">echo</span> off</span><br><span class="line">reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\<span class="number">18</span>D1D00D0100" /v "osvc" /t REG_BINARY /d "<span class="number">0000</span>" /f</span><br><span class="line">reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\<span class="number">18</span>D1D00D0100" /v "SkipContainerIdQuery" /t REG_BINARY /d "<span class="number">01000000</span>" /f</span><br><span class="line">reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\<span class="number">18</span>D1D00D0100" /v "SkipBOSDescriptorQuery" /t REG_BINARY /d "<span class="number">01000000</span>" /f</span><br><span class="line"></span><br><span class="line"><span class="built_in">pause</span></span><br></pre></td></tr></tbody></table></figure><p></p></li><li><p>(刷系统为可选项) 系统刷为 LineageOS 参考:https://wiki.lineageos.org/devices/sagit/install</p></li><li><p> 刷入 twrp, 参考: https://twrp.me/xiaomi/xiaomimi6.html, img 下载:https://dl.twrp.me/sagit/</p><ul><li><code>fastboot flash recovery ./twrp-xxx.img</code></li></ul></li><li><p>刷入 magisk (可以先刷入 twrp, 参考 https://dl.twrp.me/sagit/)https://github.com/topjohnwu/Magisk</p><ul><li>下载最新的 magisk apk 文件,后缀改为 zip</li><li> 在 twrp 中选择对应的 zip 文件刷入,如果是 LineageOS 的 recovery,可以适用 adb sideload 刷入</li><li>重启后打开 magisk, 按照提示进行后续操作,按推荐步骤执行即可</li></ul></li><li><p>给 shell 赋予 root 权限,打开开发者模式,打开 USB 调试,打开 USBroot 调试</p><ul><li><code>adb shell</code> 连接手机</li><li><code>su</code> 如果执行失败,去 magisk 的 root 权限管理中打开com.android.shell 包的 root 权限</li><li>再次尝试 <code>su</code></li></ul></li></ol><h2 id="linuxdeploy安装部署和配置">3 LinuxDeploy 安装部署和配置</h2><ol type="1"><li><p>LinuxDeploy 应用安装</p><ul><li>官方的 <a href="https://github.com/meefik/linuxdeploy">LinuxDeploy</a>,可以先尝试一下,小米 6 使用官网的 app 一直安装有问题,所以最终没有使用官方的 apk</li><li> 我的小米 6 使用 <a href="https://github.com/lateautumn233/Linuxdeploy-Pro">LinuxDeploy-Pro</a>,看维护时间还比较新,官方地址貌似停止维护了</li><li>下载 apk 安装,打开时授予 root 权限</li></ul></li><li><p> LinuxDeploy 配置</p><p>应用右下角按钮设置安装选项,这里列一下我的选择,可以根据喜好或者实际安装情况决定</p><ul><li>chroot 不用改</li><li> Debian</li><li>arm64</li><li>stable</li><li>http://mirrors.ustc.edu.cn/debian小米 6 这里设置 <strong>https 连不上</strong> , 只有 http 能用</li><li> file</li><li><code>${EXETERNAL_STORAGE}/debian.img</code></li><li>81920 镜像大小我给了 80G, 开始只给 10G, 后面软件安装发现不够用了,不过之后也可以扩容,只是费时间</li><li> ext4 不用改</li><li>用户名和密码自由设置</li><li> en_US.UTF-8</li><li>Auto DNS 设置可以改为好用的地址,我这里选的自动</li><li>勾选 INIT, 小米 6 上 run-parts 我没有调教好,这里选的<strong>sysv</strong>, 用于开启容器时自动执行一些任务</li><li>勾选 MOUNTS, <code>/sdcard:/sdcard</code>主要是将安卓内部存储挂载到 Linux 系统内</li><li>勾选 SSH, 该步骤是必须的,否则安装的 Linux 不好访问</li></ul></li><li><p>部署 Linux</p><p>按照上述配置完成后,返回主界面,点击右上 "三点", 选择 "install",开始安装部署</p><ul><li>若提示联网问题,先检查设备是否联网,镜像配置是否正确,是否使用 http 协议</li><li>更改配置后,先点 stop 按钮卸载分区,之后再次点 install 安装</li><li>安装过程必须保证没有报错,若有报错,可能需要搜索相关问题,解决后重新安装</li><li>若使用该方法怎样都安装不成功,可以参考 ((20230730133322-tx8cs9x' 备份与恢复 ')) 一节的方法,直接导入合适架构的备份包即可</li></ul></li><li><p>启动容器,ssh 连接</p><ul><li>点击 start 即可启动容器</li><li>启动成功后可以通过 ssh 连接到 Linux</li><li> 可以局域网的 PC 通过 IP 连接</li><li>也可以手机上安装 JuiceSSH, 通过 localhost 或者 127.0.0.1 连接</li><li>启动容器后,最好 sudo su 切<strong>换到 root 用户</strong>操作,之后所有操作都基于 root 用户</li></ul></li><li><p>开机自启动,CPU 锁,Wi-Fi 锁</p><p>打开 LinuxDeploy 左上角菜单</p><ul><li>Lock Wi-Fi 应用运行时保持 WiFi 打开</li><li> Wake lock 应用运行时保持 CPU 运转,即使锁屏</li><li> Autostart 当 Android 启动后自动运行应用,并运行默认配置的容器,非常有用</li><li> Autostart delay 自启动延时 我设置了 10 秒</li></ul></li><li><p>备份与恢复</p><p>Telnet 服务: LinuxDeploy 左上角菜单设置,Services, TELNET 和 HTTP 都打开,取消勾选 TELNET 中的 Localhost, HTTP 服务的 Accessrestriction 中 A 之后设置允许连接的 IP 地址比如 <code>A:192.168.31.27 D:*</code></p><p>这里的 HTTP 服务是由 httpd 提供,支持配置多个 <code>A:xxx</code> 添加多个可以访问的 IP 地址</p><p>浏览器访问 <code>http://ip:5080</code> 打开 Linux DeployTerminal 的 Telnet 终端</p><ul><li><p>备份与恢复命令</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">su <span class="comment"># 切换为root</span></span><br><span class="line"><span class="built_in">cd</span> /sdcard</span><br><span class="line">linuxdeploy stop -u <span class="comment"># 停止容器并卸载分区</span></span><br><span class="line">linuxdeploy <span class="built_in">export</span> /sdcard/debian-rootfs-20230729.tgz <span class="comment"># 等待完成即可, 之后可以拷贝一份到电脑上</span></span><br><span class="line">linuxdeploy import /sdcard/debian-rootfs-20230729.tgz <span class="comment"># 导入操作</span></span><br><span class="line">linuxdeploy start <span class="comment"># 运行容器</span></span><br></pre></td></tr></tbody></table></figure></li><li><p>如果上述的安装不成功,也可以下载合适架构的备份包,直接导入[小米 6 的架构为 arm64 (aarch64)]</p><ul><li>ubuntu 18 LTS arm64(http://hub.meefik.ru/rootfs/ubuntu_arm64.tgz)</li><li>debian 10 arm64 (http://hub.meefik.ru/rootfs/debian_arm64.tgz)</li></ul></li></ul></li><li><p> 镜像扩容</p><p>先打开 telnet 访问,切 root 用户</p><p></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 从/dev/zero取二进制0, 块大小为1M, 一共4096个块, 追加到debian.img (扩容4GB)</span></span><br><span class="line"><span class="built_in">dd</span> <span class="keyword">if</span>=/dev/zero bs=1048576 count=4096 >> /sdcard/debian.img</span><br><span class="line"></span><br><span class="line"><span class="comment"># 强制检查(修复)镜像的硬盘分区</span></span><br><span class="line">e2fsck -f /sdcard/debian.img</span><br><span class="line"></span><br><span class="line"><span class="comment"># 调整分区大小, 同步文件系统容量?</span></span><br><span class="line">resize2fs /sdcard/debian.img</span><br></pre></td></tr></tbody></table></figure><p></p></li><li><p>LinuxDeploy 中的一些限制</p><ul><li>不是基于 systemd 运行的,systemctl, service 等命令无法正常工作</li><li>不支持 docker, 如果想要支持,需要自己编译 android 内核,修改编译选项,相当麻烦</li></ul></li></ol><h2 id="linux系统配置">4 Linux 系统配置</h2><p>我的小米 6 系统部署启动成功后,发现 ssh 连接正常,apt 更新也正常,但是 ping 不通任何域名和地址,包括 127.0.0.1,curl 和 wget 等应用也无法使用</p><ol type="1"><li><p>解决联网问题 尝试了很多方法,只能让 root 用户正常联网</p><ul><li><p>编辑 <code>/etc/group</code> 在 aid_inet (3003),aid_net_raw (3004) 的分组中添加需要的用户名,多个用户名用逗号分开</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">aid_inet:x:3003:fetasty,root</span><br><span class="line">aid_net_raw:x:3004:fetasty,root</span><br></pre></td></tr></tbody></table></figure></li></ul></li><li><p>解决 ssh 连接后,无法 tab 补全,无法查看历史命令,没有颜色显示问题</p><ul><li><p>编辑 /etc/passwd 在对应用户名后将 sh 更改为 bash</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fetasty:x:60000:60000::/home/fetasty:/bin/bash</span><br></pre></td></tr></tbody></table></figure></li><li><p>编辑~/.bashrc 取消注释其中要显示颜色的行</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source ~/.bashrc</span><br></pre></td></tr></tbody></table></figure></li></ul></li><li><p>supervisor 自启动服务配置 (chroot 中的 Linux, systemd, systemctl,service 等命令并不好用,不好设置自启动)</p><p>这里我们使用 <a href="http://supervisord.org/">supervisor</a> 管理其余服务进程,主要设置好 supervisor 自启动和配置</p><ul><li><p><code>apt-get install supervisor</code> 安装 supervisor,用于管理自启动进程 (按照官网的意思,应该使用 pip 安装,但是我实际使用时并不太顺利)</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~</span><br><span class="line"><span class="comment"># curl -O https://bootstrap.pypa.io/get-pip.py</span></span><br><span class="line"><span class="comment"># python3 get-pip.py # 运行失败, 安装pip失败, 提示应该使用apt install python3-xxx来安装</span></span><br><span class="line">apt install python3-pip <span class="comment"># 安装成功</span></span><br><span class="line">pip3 config <span class="built_in">set</span> global.index-url https://pypi.mirrors.ustc.edu.cn/simple</span><br><span class="line">pip3 config list</span><br><span class="line"><span class="comment"># pip3 install supervisor # 失败 https://stackoverflow.com/questions/75608323/how-do-i-solve-error-externally-managed-environment-everytime-i-use-pip3</span></span><br><span class="line">pip3 install supervisor --break-system-packages <span class="comment"># 命令行提示最好先venv创建一个环境再安装, 太麻烦了, 不如apt直接装</span></span><br></pre></td></tr></tbody></table></figure></li><li><p>确认容器启动配置中为 <strong>sysv</strong>,小米 6 上测试了 run-parts 方式的自启动无效 参考 <a href="https://blog.csdn.net/qq_43445867/article/details/131799629">LinuxDeploy 应用自启动</a></p></li><li><p><code>~~nano /etc/init.d/supervisord.sh~~</code> ~~编辑 supervisord 应用的启动脚本,该脚本必须按照<del><a href="https://wiki.debian.org/LSBInitScripts"><del>规范</del></a></del>编写~~</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"></span><br><span class="line"><span class="comment">### BEGIN INIT INFO</span></span><br><span class="line"><span class="comment"># Provides: supervisord</span></span><br><span class="line"><span class="comment"># Required-Start: $network $remote_fs $local_fs</span></span><br><span class="line"><span class="comment"># Required-Stop: $network $remote_fs $local_fs</span></span><br><span class="line"><span class="comment"># Default-Start: 2 3 4 5</span></span><br><span class="line"><span class="comment"># Default-Stop: 0 1 6</span></span><br><span class="line"><span class="comment"># Short-Description: supervisord start</span></span><br><span class="line"><span class="comment"># Description: supervisord run script</span></span><br><span class="line"><span class="comment">### END INIT INFO</span></span><br><span class="line"></span><br><span class="line">/usr/bin/supervisord -c /etc/supervisor/supervisord.conf</span><br><span class="line"></span><br><span class="line"><span class="built_in">exit</span> 0</span><br></pre></td></tr></tbody></table></figure><ul><li><code>chmod +x /etc/init.d/supervisord.sh</code> 赋予执行权限</li><li><code>update-rc.d supervisord.sh defaults</code> 设置开机自启动</li><li><code>update-rc.d -f supervisord.sh remove</code>移除开机自启动</li></ul></li><li><p>后续发现 apt 安装 supervisor 后,<code>/etc/init.d</code>目录下存在一个 supervisor 文件,但是并未成功自启动(lighttpd 安装后可正常自启动)</p><ol type="1"><li><p>给该文件添加运行权限</p></li><li><p>该文件前面有一段注释,不知道是否符合<a href="https://wiki.debian.org/LSBInitScripts">规范</a> , 删除了<code>### BEGIN INIT INFO</code> 之前的一段注释</p></li><li><p>执行 update-rc.d 命令</p><p></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">update-rc.d supervisor defaults</span><br><span class="line">update-rc.d supervisor <span class="built_in">enable</span></span><br></pre></td></tr></tbody></table></figure><p></p></li></ol></li><li><p>supervisor <a href="http://supervisord.org/installing.html#creating-a-configuration-file">配置生成</a><a href="http://supervisord.org/configuration.html">配置说明</a></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo_supervisord_conf > /etc/supervisor/supervisord.conf <span class="comment"># 生成配置模板</span></span><br></pre></td></tr></tbody></table></figure><p>修改配置,小米 6 上的 supervisord 使用 sock 文件一直有报错,我修改成了 http 方式,注释了 unix_http_server 部分,打开了 inet_http_server 部分 (可能与之前的分组有同样关系?)</p><figure class="highlight ini"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">;[unix_http_server]</span></span><br><span class="line"><span class="comment">;file=/tmp/supervisor.sock ; the path to the socket file</span></span><br><span class="line"><span class="comment">;chmod=0777 ; socket file mode (default 0700)</span></span><br><span class="line"><span class="comment">;chown=root:root ; socket file uid:gid owner</span></span><br><span class="line"><span class="comment">;username=user ; default is no username (open server)</span></span><br><span class="line"><span class="comment">;password=123 ; default is no password (open server)</span></span><br><span class="line"></span><br><span class="line"><span class="section">[inet_http_server]</span> <span class="comment">; inet (TCP) server disabled by default</span></span><br><span class="line"><span class="attr">port</span>=*:<span class="number">9001</span> <span class="comment">; ip_address:port specifier, *:port for all iface</span></span><br><span class="line"><span class="comment">;username=user ; default is no username (open server)</span></span><br><span class="line"><span class="comment">;password=123 ; default is no password (open server)</span></span><br><span class="line"></span><br><span class="line"><span class="section">[supervisorctl]</span></span><br><span class="line"><span class="comment">;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket</span></span><br><span class="line"><span class="attr">serverurl</span>=http://<span class="number">127.0</span>.<span class="number">0.1</span>:<span class="number">9001</span> <span class="comment">; use an http:// url to specify an inet socket</span></span><br><span class="line"></span><br><span class="line"><span class="section">[include]</span></span><br><span class="line"><span class="attr">files</span> = /etc/supervisor/conf.d/*.conf</span><br></pre></td></tr></tbody></table></figure></li><li><p>设置好 supervisor 的自启动后,stop 再 start,看命令行中是否有 supervisor 的运行提示,若设置成功,其余需要自启动的进程就可以交给 supervisor 来管理</p></li><li><p> supervisord 服务启动后,会监听 9001 端口,用于控制和查看进程的状态</p></li><li><p>添加新的进程配置文件后 执行 <code>supervisorctl reload</code>刷新,再访问 9001 的 http 服务,就可以查看进程状态</p></li><li><p><code>supervisorctl reload</code> 命令会重启所有管理的进程,如果只是加载新添加的配置可以运行以下指令</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">supervisorctl reread <span class="comment"># 重新读取配置文件</span></span><br><span class="line">supervisorctl update <span class="comment"># 刷新配置到进程组</span></span><br></pre></td></tr></tbody></table></figure><p>之后可以在 supervisor 管理页面看到对应的进程配置</p></li><li><p>如果需要配置多个环境变量,可以在 Environment 字段这样填写</p><figure class="highlight ini"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">environment</span>=KEY=<span class="string">"val:123"</span>,KEY2=<span class="string">"val,456"</span></span><br></pre></td></tr></tbody></table></figure></li></ul></li></ol><p>常用命令</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">free -h <span class="comment"># 查看内存占用</span></span><br><span class="line">top <span class="comment"># 查看资源占用最多的进程</span></span><br><span class="line">ps aux <span class="comment"># 查看进程列表</span></span><br><span class="line">ip addr <span class="comment"># 查看ip</span></span><br><span class="line">ss -anptu <span class="comment"># t(tcp) u(udp) 查看网络连接</span></span><br><span class="line"><span class="built_in">df</span> -h <span class="comment"># 查看磁盘空间</span></span><br><span class="line"><span class="built_in">du</span> -h --max-depth=1 /home <span class="comment"># 查看某个文件夹下的各文件/文件夹大小统计</span></span><br><span class="line"><span class="comment"># 查看用户信息 (uid, 所在分组) 用户需要在3003,3004分组中才具有网络访问权限</span></span><br><span class="line"><span class="built_in">id</span> [username]</span><br><span class="line"><span class="comment"># 编辑文件 ctrl-x ctrl-k alt-u alt-e</span></span><br><span class="line">nano /etc/apt/source.list</span><br><span class="line"><span class="comment"># 编辑用户组信息</span></span><br><span class="line">nano /etc/group</span><br><span class="line">passwd <span class="comment"># 设置当前用户密码</span></span><br><span class="line"><span class="built_in">chmod</span> a+rx xxx.sh <span class="comment"># a </span></span><br></pre></td></tr></tbody></table></figure><h2 id="常用软件">5 常用软件</h2><h3 id="lighttpd-轻量web服务">5.1 lighttpd 轻量 Web 服务</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt install lighttpd</span><br></pre></td></tr></tbody></table></figure><p>安装完成后已经自动在 /etc/init.d 目录下创建自启动配置,运行配置在 <code>/etc/lighttpd/lighttpd.conf</code>,默认网站路径为 <code>/var/www/html/</code></p><p>默认配置我没有改动,监听 80 端口,主要用于展示一个所有服务的导航页面,因为且换网络环境时服务器 IP 会变,想弄个方便的导航页,根据 hostname 值自动调整导航链接</p><ul><li><p>index.html 源码,使用 bootstrap 稍微修饰了一下,其实没啥必要</p><figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!doctype <span class="keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en-US"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"shortcut icon"</span> <span class="attr">href</span>=<span class="string">"#"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>Services List<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h1</span>></span>Services List<span class="tag"></<span class="name">h1</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"services"</span> <span class="attr">class</span>=<span class="string">"list-group"</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="tag"><<span class="name">script</span>></span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">let</span> services = [</span></span><br><span class="line"><span class="language-javascript"> [<span class="string">"Supervisor"</span>, <span class="number">9001</span>, <span class="string">""</span>],</span></span><br><span class="line"><span class="language-javascript"> [<span class="string">"Siyuan"</span>, <span class="number">6806</span>, <span class="string">""</span>],</span></span><br><span class="line"><span class="language-javascript"> [<span class="string">"Cloudreve"</span>, <span class="number">5212</span>, <span class="string">""</span>],</span></span><br><span class="line"><span class="language-javascript"> [<span class="string">"Cloudreve Admin"</span>, <span class="number">5212</span>, <span class="string">"/admin"</span>],</span></span><br><span class="line"><span class="language-javascript"> [<span class="string">"V2raya"</span>, <span class="number">2017</span>, <span class="string">""</span>]</span></span><br><span class="line"><span class="language-javascript"> ];</span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">let</span> container = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">"#services"</span>);</span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">let</span> hostname = <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">hostname</span>;</span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">let</span> content = <span class="string">""</span>;</span></span><br><span class="line"><span class="language-javascript"> services.<span class="title function_">forEach</span>(<span class="function">(<span class="params">service</span>) =></span> {</span></span><br><span class="line"><span class="language-javascript"> content += <span class="string">"<a class=\"list-group-item list-group-item-action\" "</span></span></span><br><span class="line"><span class="language-javascript"> + <span class="string">"target=\"_blank\" "</span></span></span><br><span class="line"><span class="language-javascript"> + <span class="string">"href=\"http://"</span></span></span><br><span class="line"><span class="language-javascript"> + hostname + <span class="string">":"</span></span></span><br><span class="line"><span class="language-javascript"> + service[<span class="number">1</span>]</span></span><br><span class="line"><span class="language-javascript"> + service[<span class="number">2</span>]</span></span><br><span class="line"><span class="language-javascript"> + <span class="string">"\">"</span></span></span><br><span class="line"><span class="language-javascript"> + service[<span class="number">0</span>]</span></span><br><span class="line"><span class="language-javascript"> + <span class="string">"</a>\n"</span>;</span></span><br><span class="line"><span class="language-javascript"> })</span></span><br><span class="line"><span class="language-javascript"> container.<span class="property">innerHTML</span> = content;</span></span><br><span class="line"><span class="language-javascript"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">href</span>=<span class="string">"/bootstrap.min.css"</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"/bootstrap.bundle.min.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></tbody></table></figure></li></ul><h3 id="开发编译环境">5.2 开发编译环境</h3><ol type="1"><li><p>rust 最好开代理安装 参考<a href="https://www.rust-lang.org/tools/install">官网安装说明</a>(可以参考字节镜像源中的说明安装,无需代理)</p><p></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl --proto <span class="string">'=https'</span> --tlsv1.2 -sSf https://sh.rustup.rs | sh</span><br></pre></td></tr></tbody></table></figure><p></p><p>设置 cargo 镜像源 这里使用<a href="http://rsproxy.cn/#getStarted">字节镜像源</a> ,其实安装也可以参考这里,还可以加快安装速度</p><p>编辑 <code>$HOME/.cargo/config</code></p><p></p><figure class="highlight ini"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[source.crates-io]</span></span><br><span class="line"><span class="attr">replace-with</span> = <span class="string">'rsproxy-sparse'</span></span><br><span class="line"><span class="section">[source.rsproxy]</span></span><br><span class="line"><span class="attr">registry</span> = <span class="string">"https://rsproxy.cn/crates.io-index"</span></span><br><span class="line"><span class="section">[source.rsproxy-sparse]</span></span><br><span class="line"><span class="attr">registry</span> = <span class="string">"sparse+https://rsproxy.cn/index/"</span></span><br><span class="line"><span class="section">[registries.rsproxy]</span></span><br><span class="line"><span class="attr">index</span> = <span class="string">"https://rsproxy.cn/crates.io-index"</span></span><br><span class="line"><span class="section">[net]</span></span><br><span class="line"><span class="attr">git-fetch-with-cli</span> = <span class="literal">true</span></span><br></pre></td></tr></tbody></table></figure><p></p></li><li><p>golang 参考<a href="https://go.dev/doc/install">官方文档</a> ,下载压缩包之后运行对应命令安装 (apt 直接安装的无法正常使用)</p><ul><li>在 <code>$HOME/.bashrc</code> 中添加<code>export PATH="$PATH:/usr/local/go/bin"</code></li></ul></li><li><p>缓存清理方法 (备份系统前最好先清理缓存)</p><ul><li>golang 清理缓存 <code>go clean -cache</code><code>go clean -modcache</code> 可以极大减小 <code>$HOME/go</code>目录大小</li><li> cargo 清理缓存 安装 cargo-cache, 运行 cargo-cache, .rustup目录貌似无法精简</li><li> yarn 清理缓存 <code>yarn cache clean</code>极大减小 <code>/usr/local/share/.cache/yarn</code> 目录大小</li></ul></li></ol><h3 id="cloudreve-网盘">5.3 cloudreve 网盘</h3><p>官网下载 arm64 版本二进制运行文件https://github.com/cloudreve/Cloudreve</p><p>创建 <code>/etc/supervisor/conf.d/cloudreve.conf</code></p><figure class="highlight ini"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[program:cloudreve]</span></span><br><span class="line"><span class="attr">directory</span>=/home/cloudreve</span><br><span class="line"><span class="attr">command</span>=/home/cloudreve/cloudreve</span><br><span class="line"><span class="attr">autostart</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">autorestart</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">stderr_logfile</span>=/var/log/cloudreve.err</span><br><span class="line"><span class="attr">stdout_logfile</span>=/var/log/cloudreve.log</span><br><span class="line"><span class="attr">environment</span>=CODENATION_ENV=prod</span><br></pre></td></tr></tbody></table></figure><h3 id="siyuan-笔记">5.4 siyuan 笔记</h3><p><strong>后端 core 程序编译</strong></p><p>siyuan 笔记我只想使用后端服务,使用浏览器访问,但是官方只提供 docker 方式的服务端部署方式,且只提供了 linux amd64 的包,需要自己编译</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /home</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/siyuan-note/siyuan.git</span><br><span class="line"><span class="built_in">cd</span> siyuan</span><br><span class="line">git checkout vx.x.x <span class="comment"># 切换到对应版本号</span></span><br></pre></td></tr></tbody></table></figure><p>修改 <code>scripts/linux-build.sh</code> 编译脚本</p><p>编译 siyuan-kernel, 其中的 GOARCH 需要从 amd64 改为 arm64,goproxy 可以更改为 <code>https://goproxy.cn</code></p><p>执行 <code>scripts/linux-build.sh</code>, 编译内核</p><p>官网下载对应版本号的 linux.tar.gz,解压后将 kernel 目录中的 siyuan-kernel 文件替换为我们自己编译生成的二进制文件</p><p>创建 <code>/etc/supervisor/conf.d/siyuan.conf</code> 其中的 <code>RUN_IN_CONTAINER</code> 环境变量配置非常重要,否则它默认以为是客户端模式运行,会定时检测 Electron 前端程序是否存在,若不存在,则一定时间后自动退出</p><figure class="highlight ini"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[program:siyuan]</span></span><br><span class="line"><span class="attr">directory</span>=/home/siyuan</span><br><span class="line"><span class="attr">command</span>=/home/siyuan/kernel/siyuan-kernel -lang zh_CN -wd /home/siyuan -workspace /root/siyuan</span><br><span class="line"><span class="attr">autostart</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">autorestart</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">stderr_logfile</span>=/var/log/siyuan.err</span><br><span class="line"><span class="attr">stdout_logfile</span>=/var/log/siyuan.log</span><br><span class="line"><span class="attr">environment</span>=RUN_IN_CONTAINER=<span class="number">1</span></span><br></pre></td></tr></tbody></table></figure><p><strong>前端资源编译</strong></p><p>安装 nodejs, 去官网看看<a href="https://nodejs.org/en/download/package-manager">包管理器安装方法</a> ,提示 Debian 的安装可以按照以下方式进行 (参考:https://github.com/nodesource/distributions)</p><ol type="1"><li><p>Download and import the Nodesource GPG key</p><p></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install -y ca-certificates curl gnupg</span><br><span class="line">sudo <span class="built_in">mkdir</span> -p /etc/apt/keyrings</span><br><span class="line">curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg</span><br></pre></td></tr></tbody></table></figure><p></p></li><li><p>Create deb repository (<code>NODE_MAJOR</code> can be changeddepending on the version you need.) 16, 18, 20</p><p></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">NODE_MAJOR=20</span><br><span class="line"><span class="built_in">echo</span> <span class="string">"deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_<span class="variable">$NODE_MAJOR</span>.x nodistro main"</span> | sudo <span class="built_in">tee</span> /etc/apt/sources.list.d/nodesource.list</span><br></pre></td></tr></tbody></table></figure><p></p></li><li><p>Run Update and Install</p><p></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install nodejs -y</span><br></pre></td></tr></tbody></table></figure><p></p></li><li><p>Uninstall</p><p></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">apt-get purge nodejs &&\</span><br><span class="line"><span class="built_in">rm</span> -r /etc/apt/sources.list.d/nodesource.list &&\</span><br><span class="line"><span class="built_in">rm</span> -r /etc/apt/keyrings/nodesource.gpg</span><br></pre></td></tr></tbody></table></figure><p></p></li></ol><p>我选择了安装 18 的 LTS 版本</p><p>设置 npm 镜像源 (后面两个提示不支持,按照下一步操作)</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 设置阿里镜像</span></span><br><span class="line">npm config <span class="built_in">set</span> registry=https://registry.npmmirror.com</span><br><span class="line">npm config <span class="built_in">set</span> disturl=https://registry.npmmirror.com/-/binary/node</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置electron仓库</span></span><br><span class="line">npm config <span class="built_in">set</span> electron_mirror=https://registry.npmmirror.com/-/binary/electron/</span><br></pre></td></tr></tbody></table></figure><p>设置失败可以直接修改文件 <code>nano ~/.npmrc</code></p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">registry=https://registry.npmmirror.com</span><br><span class="line">disturl=https://registry.npmmirror.com/-/binary/node</span><br><span class="line">electron_mirror=https://registry.npmmirror.com/-/binary/electron/</span><br></pre></td></tr></tbody></table></figure><p>安装 yarn, pnpm</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm install -g yarn</span><br><span class="line">npm install -g pnpm</span><br></pre></td></tr></tbody></table></figure><p>在 siyuan 根目录运行<code>./scripts/linux-build.sh</code> 即可</p><h3 id="v2raya-代理">5.5 v2raya 代理</h3><p>安装 v2raya 参考<a href="https://v2raya.org/docs/prologue/installation/debian/">官方文档</a></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 添加软件源安装</span></span><br><span class="line">wget -qO - https://apt.v2raya.org/key/public-key.asc | sudo <span class="built_in">tee</span> /etc/apt/trusted.gpg.d/v2raya.asc</span><br><span class="line"><span class="built_in">echo</span> <span class="string">"deb https://apt.v2raya.org/ v2raya main"</span> | sudo <span class="built_in">tee</span> /etc/apt/sources.list.d/v2raya.list</span><br><span class="line">sudo apt update</span><br><span class="line">sudo apt install v2raya</span><br></pre></td></tr></tbody></table></figure><p>下载 <a href="https://github.com/v2fly/v2ray-core">v2fly/v2ray-core</a>v2ray-linux-arm64-v8a</p><p>编辑 <code>/etc/supervisor/conf.d/v2raya.conf</code> 其中的<code>--v2ray-bin</code> 选项用于配置 v2ray-core 文件路径</p><figure class="highlight ini"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[program:v2raya]</span></span><br><span class="line"><span class="attr">directory</span>=/usr/bin</span><br><span class="line"><span class="attr">command</span>=/usr/bin/v2raya --v2ray-bin /home/v2ray/v2ray</span><br><span class="line"><span class="attr">autostart</span>=<span class="literal">false</span></span><br><span class="line"><span class="attr">autorestart</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">stderr_logfile</span>=/var/log/v2raya.err</span><br><span class="line"><span class="attr">stdout_logfile</span>=/var/log/v2raya.log</span><br><span class="line"><span class="attr">environment</span>=V2RAYA_LOG_FILE=/var/log/v2raya/v2raya.log</span><br></pre></td></tr></tbody></table></figure><p>这里没有设置为自启动,根据需求配置</p><p>打开进程后默认监听 2017 端口,访问可以配置选项,"port sharing" 打开后,可以将代理端口共享到局域网中,供其他设备使用</p><h3 id="code-server">5.6 code-server</h3><p>自部署,可以通过浏览器访问的 VS Code</p><p>安装参考<a href="https://github.com/coder/code-server/tree/main#getting-started">官方文档</a></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> http_proxy=http://xxxx:xxx</span><br><span class="line"><span class="built_in">export</span> https_proxy=<span class="variable">$http_proxy</span></span><br><span class="line">curl -fsSL https://code-server.dev/install.sh | sh</span><br></pre></td></tr></tbody></table></figure><p>使用方式参考<a href="https://github.com/coder/code-server/blob/main/docs/guide.md#expose-code-server">官方文档</a></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Replaces "auth: password" with "auth: none" in the code-server config.</span></span><br><span class="line">sed -i.bak <span class="string">'s/auth: password/auth: none/'</span> ~/.config/code-server/config.yaml</span><br></pre></td></tr></tbody></table></figure><p>编辑 <code>/etc/supervisor/conf.d/code-server.conf</code></p><figure class="highlight ini"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[program:code-server]</span></span><br><span class="line"><span class="attr">directory</span>=/usr/bin</span><br><span class="line"><span class="attr">command</span>=/usr/bin/code-server</span><br><span class="line"><span class="attr">autostart</span>=<span class="literal">false</span></span><br><span class="line"><span class="attr">autorestart</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">stderr_logfile</span>=/var/log/code-server.err</span><br><span class="line"><span class="attr">stdout_logfile</span>=/var/log/code-server.log</span><br><span class="line">environment=</span><br></pre></td></tr></tbody></table></figure><p>暴露服务端口,这部分最简单的方式是按照官方提示,使用 SSH Forwarding,不然比较麻烦,直接暴露 HTTP 端口,使用会提示不安全,且很多功能会失效</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -N disables executing a remote shell</span></span><br><span class="line">ssh -N -L 8080:127.0.0.1:8080 [user]@<instance-ip></span><br><span class="line"><span class="comment"># ssh -N -L 8080:127.0.0.1:8080 [email protected]</span></span><br></pre></td></tr></tbody></table></figure><h2 id="cpu调度问题探究">6 CPU 调度问题探究</h2><p>使用 lineageos 时关闭屏幕会自动开启 doze 模式,目前只能是 usb 默认文件传输,接上电脑使用 [或者刷系统看看,honor v10 没有刷 lineageos 没有该问题]</p><p><strong>刷回小米的 MIUI 系统并禁用一部分系统应用,效果还可以</strong></p><p>以下内容是探索该问题的一些思路历程</p><p>问题定位:https://blog.csdn.net/wenzhi20102321/article/details/130977176</p><p>查看安卓日志</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">adb shell</span><br><span class="line">logcat -c # 先清空日志</span><br><span class="line"># 进行操作,拔掉电源线,关闭屏幕</span><br><span class="line"># 再连接usb线,打开adb shell</span><br><span class="line">logcat threadtime | grep -i -E "Wifi|Power" # 查看和电源与wifi相关的日志</span><br></pre></td></tr></tbody></table></figure><p>注意到以下日志</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">09-28 22:22:47.166 1664 1664 I FingerprintManager: onPowerPressed</span><br><span class="line">09-28 22:22:47.167 1664 1664 I PowerManagerService: Going to sleep due to power_button (uid 1000, screenOffTimeout=60000, activityTimeoutWM=-1, maxDimRatio=0.20000005, maxDimDur=7000)...</span><br><span class="line">09-28 22:22:47.670 976 976 D SurfaceFlinger: Setting power mode 0 on display 0</span><br><span class="line">09-28 22:22:47.848 976 976 D SurfaceFlinger: Finished setting power mode 0 on display 0</span><br><span class="line">09-28 22:22:47.850 1664 2267 D SurfaceControl: Excessive delay in setPowerMode()</span><br><span class="line">09-28 22:22:47.850 1664 1943 I DisplayPowerController[0]: BrightnessEvent: disp=0, physDisp=local:0, brt=0.0, initBrt=0.0, rcmdBrt=NaN, preBrt=NaN, lux=0.0, preLux=0.0, hbmMax=1.0, hbmMode=off, rbcStrength=50, powerFactor=1.0, thrmMax=1.0, wasShortTermModelActive=false, flags=, reason=screen_off, autoBrightness=true</span><br><span class="line">09-28 22:22:47.851 917 917 I android.hardware.power-service-qti: Power setMode: 7 to: 0</span><br><span class="line">09-28 22:22:47.851 917 917 E QTI PowerHAL: Failed to acquire lock for hint_id: 1040.</span><br><span class="line">09-28 22:22:47.853 1664 1943 I PowerManagerService: Dozing...</span><br></pre></td></tr></tbody></table></figure><p>可能和 doze 模式打开相关</p><p>搜索如何关闭 doze 模式,参考https://forum.xda-developers.com/t/disable-doze.4407685/,以及 GPT 中询问 "怎样在 adb 中使用命令禁止 doze 模式"</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">adb shell dumpsys deviceidle disable # 使用该命令可以禁用doze模式</span><br><span class="line">adb shell dumpsys deviceidle enable # 使用该命令可以禁用doze模式</span><br><span class="line">adb shell dumpsys deviceidle whitelist +<package_name> # 在特定应用上禁用doze模式</span><br><span class="line">adb shell dumpsys deviceidle whitelist -<package_name> # 去掉特定应用禁用doze模式</span><br></pre></td></tr></tbody></table></figure><p>实测在 LinuxDeploy 中设置中打开 <code>Lock screen</code> 和 <code>Wake lock</code>,并<strong>接通电源</strong>使用,可以保持较为流畅的体验,"Kerneladiutor"并不能解决 CPU" 睡眠 " 问题</p><p><del>实际上打开</del><code>Lock screen</code><del>开关之后,并不会导致屏幕常亮,而且可以照常锁屏,不会导致睡眠问题</del></p><p><del>但是打开</del><code>Lock screen</code><del>开关后电量会掉的比较快,所以使用时打开该开关,待机时关闭该开关即可</del></p><p>(当然,也有可能是将 USB 默认配置改成了文件传输,才让它保持 CPU),按照上述设置,打开 Lock Screen 但是接手机充电器试试,出现睡眠问题</p><p>开发者选项中开启 "Stay awake", 之后关闭屏幕,还是卡顿</p><p>参考:https://stackoverflow.com/questions/7617459/how-to-keep-cpu-from-sleeping-when-screen-is-turned-off-in-android</p><p>参考: https://developer.android.com/training/scheduling/wakelock</p><p><del>可能是 LinuxDeploy 中的 CPU 锁没有生效</del></p><p>现象:实际使用的时候,已经在 LinuxDeploy 中打开了 <code>Wifi Lock</code> 和 <code>CPU Wake Lock</code>,但是有时候还是发现打开笔记会卡顿,刷新会卡 LOGO 界面,但是点亮屏幕就会非常快刷新页面,不存在卡顿</p><p>这很有可能是 CPU 调度策略引起的问题,<strong>锁屏</strong>后 CPU 进入了 "Deep Sleep" 状态</p><p>通过以下命令可以看到 CPU 核心的运行情况,但是当卡顿情况发生时,命令的输入都会变得卡顿</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">lscpu -e</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果提示命令不存在, 需要下载util-linux</span></span><br><span class="line">apt-get install util-linux</span><br></pre></td></tr></tbody></table></figure><p>注意: <strong>使用 Kerneladiutor 设置后还是无法避免锁屏后手机进入 "睡眠" 模式导致卡顿,以下内容可以选择性忽略</strong></p><p>通过 <code>Kernel adiutor</code> 可以调整 CPU 运行策略</p><p>下载地址:https://f-droid.org/en/packages/com.nhellfire.kerneladiutor</p><p>在 CPU 选项中,更改 CPU Govemor</p><p>以下内容引用自 ChatGPT</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">Performance(性能):</span><br><span class="line">Performance模式将CPU设置为最高性能状态,以实现最佳的性能表现。这意味着CPU频率会尽可能地提高,以获得更高的计算能力。但是,这也会导致电池更快地耗尽,因此通常不适用于需要长时间使用电池的情况。</span><br><span class="line"></span><br><span class="line">Powersave(节能):</span><br><span class="line">Powersave模式旨在最大程度地减少CPU功耗,从而延长电池寿命。它会将CPU频率降低到较低的水平,以降低性能,但可以显著减少电池的消耗。这适用于长时间不需要高性能的情况。</span><br><span class="line"></span><br><span class="line">Ondemand(按需):</span><br><span class="line">Ondemand模式是一种动态调整CPU频率的模式,它根据系统负载自动调整CPU频率。当系统负载较低时,CPU频率会降低以节省电池电量,而在需要更多性能时,它会提高频率以提供更好的响应性能。</span><br><span class="line"></span><br><span class="line">Interactive(交互式):</span><br><span class="line">Interactive模式是一种类似于Ondemand的动态调整模式,但更加灵活。它更快地响应负载变化,以提供更好的用户体验。这个模式在需要快速响应输入和任务切换的情况下非常有用。</span><br><span class="line"></span><br><span class="line">Conservative(保守):</span><br><span class="line">Conservative模式也是一种动态调整模式,但相对于Ondemand和Interactive来说更加保守。它会慢慢地增加或降低CPU频率,以更平滑地适应负载变化。</span><br><span class="line"></span><br><span class="line">Userspace(用户空间):</span><br><span class="line">Userspace模式允许用户手动设置CPU频率,而不是依赖于内核的自动调整。用户可以根据自己的需求来设置CPU频率,但需要小心,以避免不稳定或过度耗电。</span><br><span class="line"></span><br><span class="line">Performance Bias(性能偏好):</span><br><span class="line">这是一种类似于Performance模式的模式,但稍微降低了CPU的性能以节省一些电量。它可以提供相对较高的性能,同时保持一定的电池寿命。</span><br></pre></td></tr></tbody></table></figure><p>可以考虑将小核设置为 Performance, 大核保持 Interactive 不变,看是否会减少卡顿 (貌似不行)</p><p>将大小核都设置为 Performance</p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>手头上的旧手机为小米 6, 本文可能部分内容只在小米 6 上适用 [xiaomi 6
sagit]</p>
<p>且本文主要讨论 LinuxDeploy (需要 root) 的方式,
非 root 用户可使用 Termux 方式</p></summary>
<category term="Linux" scheme="https://fetasty.github.io/categories/Linux/"/>
<category term="Linux" scheme="https://fetasty.github.io/tags/Linux/"/>
<category term="Android" scheme="https://fetasty.github.io/tags/Android/"/>
</entry>
<entry>
<title>健康生活清单</title>
<link href="https://fetasty.github.io/posts/1ef19147/"/>
<id>https://fetasty.github.io/posts/1ef19147/</id>
<published>2022-03-07T13:28:25.000Z</published>
<updated>2023-06-19T06:55:27.941Z</updated>
<content type="html"><![CDATA[<p>现在多少年轻人都莫名其妙的大病或猝死,不好的生活习惯会让我们的身体一直处于亚健康状态,后面可能任何一个小的触发点都能是压垮骆驼的最后一根稻草,比如生个气喝个酒甚至猛然的剧烈运动一下都可能直接人没了</p><span id="more"></span><p>一份简单的健康生活清单,说着简单,但坚持做下来不简单</p><ul><li>饮食<ul><li><span style="color: green">多喝水</span></li><li><span style="color: green">多吃蔬菜水果</span></li><li><span style="color: orange">少吃油炸烧烤腌制</span> (含致癌物)</li><li><span style="color: red"> 少吃游离糖,少吃零食,少喝奶茶</span>(高糖高热量,危害多到写不下)</li><li><span style="color: red"> 不饮酒,不喝含酒精饮料</span>(含酒精饮料为一级致癌物 (与黄曲霉素一个等级))</li></ul></li><li> 作息<ul><li><span style="color: green">早睡早起</span> (熬夜的危害实在太多了,都懒得写)</li><li><span style="color: green"> 保持午休</span> (30 分钟左右即可,双相睡眠对身体非常好)</li></ul></li><li> 活动<ul><li><span style="color: green">保持锻炼</span>(每周至少 3 次不少于 30 分钟的运动)</li><li><span style="color: red"> 不要长时间埋头,电脑垫高</span> (保护颈椎,出问题时才知道多严重)</li></ul></li></ul><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>现在多少年轻人都莫名其妙的大病或猝死,
不好的生活习惯会让我们的身体一直处于亚健康状态,
后面可能任何一个小的触发点都能是压垮骆驼的最后一根稻草,
比如生个气喝个酒甚至猛然的剧烈运动一下都可能直接人没了</p></summary>
<category term="生活" scheme="https://fetasty.github.io/categories/life/"/>
</entry>
<entry>
<title>C++ 中 const 与 constexpr 的区别</title>
<link href="https://fetasty.github.io/posts/106f98c5/"/>
<id>https://fetasty.github.io/posts/106f98c5/</id>
<published>2022-03-07T13:25:57.000Z</published>
<updated>2023-06-19T08:50:35.370Z</updated>
<content type="html"><![CDATA[<p>原文地址: <a href="https://www.cnblogs.com/fortunely/p/14550145.html">const 和 constexpr 区别与联系</a></p><p>提到 const 和 constexpr, 就需要引入常量表达式。常量表达式是指值不会改变,并且编译过程就能得到计算结果的表达式. => 编译阶段就能得到值,并且不能改变.</p><span id="more"></span><p><strong>const 修饰对象无法修改,constexpr 更侧重于修饰对象编译期确定且无法修改. </strong>具体区别,体现在以下两个方面:</p><h2 id="修饰变量">修饰变量</h2><p><strong>const 变量,表示一个变量无法改变,但初值并不确定,不能在编译阶段决定. </strong></p><p>比如,</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> <span class="type">int</span> sz = <span class="built_in">get_size</span>(); <span class="comment">// 虽然sz无法改变, 但get_size()</span></span><br></pre></td></tr></tbody></table></figure><p>编译阶段无法确定值,也就是说 sz 不是常量表达式</p><p><strong>constexpr 变量,编译器在编译阶段验证变量是否为一个常量表达式.</strong></p><p>constexpr 侧重变量初值编译阶段确定,且无法修改.如果认定变量是一个常量表达式,就把它声明称 constexpr 类型.</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> mf = <span class="number">20</span>; <span class="comment">// 字面量20是常量表达式</span></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> limit = mf + <span class="number">1</span>; <span class="comment">// mf + 1是常量表达式</span></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> sz = <span class="built_in">size</span>(); <span class="comment">// 只有当size是constexpr函数时, 才是正确的</span></span><br></pre></td></tr></tbody></table></figure><h2 id="修饰指针">修饰指针</h2><p>const 修饰指针分为两种情况:顶层 const, 底层 const.</p><p><strong>顶层 const 代表指针变量自身无法修改;底层 const 代表指针所指对象无法修改.</strong></p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> i = <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span> *<span class="type">const</span> p1 = &i; <span class="comment">// 顶层const</span></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> *p2 = &i; <span class="comment">// 底层const</span></span><br><span class="line"></span><br><span class="line">p1 = <span class="keyword">new</span> <span class="built_in">int</span>(<span class="number">20</span>); <span class="comment">// 错误, 顶层const指针自身无法修改</span></span><br><span class="line">p2 = <span class="keyword">new</span> <span class="built_in">int</span>(<span class="number">30</span>); <span class="comment">// 正确, 底层const指针可以修改</span></span><br><span class="line">*p1 = <span class="number">40</span>; <span class="comment">// 正确, 顶层const指针指向的对象可以修改</span></span><br><span class="line">*p2 = <span class="number">40</span>; <span class="comment">// 错误, 底层const指针指向的对象无法修改</span></span><br></pre></td></tr></tbody></table></figure><p>constexpr 修饰指针,仅对指针有效,与指针所指对象无关</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// j的定义必须放在函数体外</span></span><br><span class="line"><span class="type">int</span> j = <span class="number">30</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 函数体内</span></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> *pp1 = &j; <span class="comment">// 等价于 int constexpr *pp1 = &j;</span></span><br><span class="line">cout << *pp1 << endl; <span class="comment">// 30</span></span><br><span class="line">*pp1 = <span class="number">40</span>;</span><br><span class="line">cout << j << endl; <span class="comment">// 40</span></span><br><span class="line">pp1 = <span class="literal">nullptr</span>; <span class="comment">// 错误, constexpr指针无法修改</span></span><br></pre></td></tr></tbody></table></figure><h2 id="修饰函数">修饰函数</h2><p>const 修饰成员函数,通常称为 const 函数,表示该函数不会修改类的状态(即不会通过任何方式修改类数据成员). 另外,const 类对象,只能调用 const 函数,确保不会修改类的数据成员.</p><p>constexpr 无法修饰成员函数,只能作为函数返回值类型,表明该函数返回的是一个编译期可确定的常量;constexpr被隐式隐式指定为内联函数,只能在类的声明中定义(.h 文件).</p><p>参见 <a href="https://blog.csdn.net/lihao21/article/details/8634876">C++ 的 const 类成员函数</a></p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// A.h</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">A</span>{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">A</span>():<span class="built_in">curSize</span>(<span class="number">10</span>) {}</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">setSize</span><span class="params">(<span class="type">int</span> size)</span> </span>{ size++; }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// const函数</span></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">size</span><span class="params">()</span> <span class="type">const</span> </span>{ <span class="keyword">return</span> curSize; } <span class="comment">// 正确示例:不写任何数据成员</span></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">size</span><span class="params">()</span> <span class="type">const</span> </span>{ curSize = <span class="number">2</span>; <span class="keyword">return</span> curSize; }; <span class="comment">// 错误示例: const函数不能修改任何类的数据成员</span></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">size</span><span class="params">()</span> <span class="type">const</span> </span>{ <span class="built_in">setSize</span>(); <span class="keyword">return</span> curSize; } <span class="comment">// 错误示例:const函数不能调用任何可能导致类的数据成员改变的函数, 也就是说, 如果调用自身成员函数, 只能调用const函数</span></span><br><span class="line"> <span class="function"><span class="type">const</span> <span class="type">int</span> <span class="title">size</span><span class="params">()</span> </span>{ <span class="keyword">return</span> curSize; } <span class="comment">// 函数返回值为const类型:函数体可以修改数据成员, 但返回类型是const, 也就是调用者无法修改</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 函数返回值为constexpr类型</span></span><br><span class="line"> <span class="function"><span class="keyword">constexpr</span> <span class="type">int</span> <span class="title">getMaxSize</span><span class="params">()</span> </span>{ <span class="keyword">return</span> INT_MAX; } <span class="comment">// 正确示例:返回常量值</span></span><br><span class="line"> <span class="comment">// 错误示例:vec.size()运行时确定, 不能在编译期决定</span></span><br><span class="line"> <span class="function"><span class="keyword">constexpr</span> <span class="type">int</span> <span class="title">getMaxSize</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> std::vector<<span class="type">int</span>> vec;</span><br><span class="line"> vec.<span class="built_in">push_back</span>(<span class="number">1</span>);</span><br><span class="line"> vec.<span class="built_in">push_back</span>(<span class="number">2</span>);</span><br><span class="line"> <span class="keyword">return</span> vec.<span class="built_in">size</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 正确:虽然看起来返回的是变量, 但编译器可确定</span></span><br><span class="line"> <span class="function"><span class="keyword">constexpr</span> <span class="type">int</span> <span class="title">getMaxSize</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> a + b;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="type">int</span> curSize;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// A.cpp</span></span><br><span class="line"><span class="comment">// 错误示例:constexpr被隐式指定为内联函数, 只能在.h 类内定义, 不能在类实现文件(.cpp)中定义</span></span><br><span class="line"><span class="function"><span class="keyword">constexpr</span> <span class="type">int</span> <span class="title">A::getMaxsize</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>原文地址: <a href="https://www.cnblogs.com/fortunely/p/14550145.html">const 和 constexpr 区别与联系</a></p>
<p>提到 const 和 constexpr, 就需要引入常量表达式。常量表达式是指值不会改变,
并且编译过程就能得到计算结果的表达式. =&gt; 编译阶段就能得到值,
并且不能改变.</p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>添加糖 - 甜蜜杀手</title>
<link href="https://fetasty.github.io/posts/90d1f41c/"/>
<id>https://fetasty.github.io/posts/90d1f41c/</id>
<published>2022-03-07T13:23:43.000Z</published>
<updated>2023-06-19T06:55:27.941Z</updated>
<content type="html"><![CDATA[<p>让人上瘾,又伤心、伤脑…… 这味调料家家都有,但劝你别多吃!</p><p>2022-03-01 14:00 来源: CCTV 回家吃饭</p><p> 糖果、冰激凌、蛋糕、饼干、巧克力…… 甜食让不少人欲罢不能,情绪不好时来一口,感觉整个世界都明媚了;时下的网红饮品奶茶,更是被戏称为 “肥宅快乐水”, 深受年轻人的喜爱~</p><p> 殊不知,大快朵颐的同时,甜食更像是一位隐形的 “甜蜜杀手”,不仅会让人慢慢 “上瘾”, 还会悄悄摧毁着你的身体!</p><span id="more"></span><h2 id="长期吃太多糖-从上到下毁全身">长期吃太多糖,从上到下毁全身</h2><p> 2012 年 2 月,发表在国际顶级学术刊物《Nature》杂志的一篇题为《公共卫生:糖的毒性真相》的文章指出:糖就像烟草和酒精一样,而且糖的危害远在脂肪和卡路里之上!</p><h3 id="糖-会诱发多种癌症">1 糖,会诱发多种癌症</h3><p> 长期高糖摄入会导致肥胖和胰岛素抵抗,造成内氧化应激、内分泌紊乱及免疫功能障碍,从而导致肿瘤的发生风险增加.</p><p> 2020 年刊发在《美国临床营养学杂志》的一项研究,对 10 万余人进行了长达 5.9 年的随访,通过饮食记录大家吃糖的情况.结果发现:</p><p> ①总糖摄入量与较高的总癌症风险相关,且这种联系主要来自乳腺癌;</p><p> ②添加糖、蔗糖、含糖饮料中的糖等与癌症风险的增加显著相关性.</p><p> 另外,瑞典科学家花 9 年时间对 8 万人进行了跟踪调查,结果显示,经常过量摄取甜食、果酱等高糖食物的人,患胰腺癌的风险要比其他人高出 70%~90%.</p><p> 而除了人人敬而远之的癌症,吃糖过多还会带来以下危害:</p><h3 id="形成龋齿">2 形成龋齿</h3><p> 摄入过多糖分食物,容易导致龋齿产生.因为在口腔中残留的糖分非常容易被细菌分解并发酵,从而产生酸性的物质,损坏牙釉质.</p><h3 id="加速皮肤老化">3 加速皮肤老化</h3><p> 摄入太多糖分时,不仅容易使皮肤松弛,滋生皱纹,肤色暗黄且没有光泽;也会使得酪氨酸酶异常活跃,加快黑色素沉淀速度,使得皮肤暗沉,容易长斑;甚至易堵塞毛孔而形成痤疮.</p><h3 id="伤大脑">4 伤大脑</h3><p> 吃太多糖,会伤害脑细胞,降低记忆力,简单来说就是吃糖过多会让人变笨.</p><h3 id="诱发心脏病">5 诱发心脏病</h3><p> 进食含糖量过高的食品会使血液中的甘油三酯升高,从而增加患心血管疾病的风险.</p><p> 另外,一项针对 11.8 万美国人的 34 年随访研究显示:每天饮用 2 次以上含糖饮料的人,死于心血管疾病的风险上升 31%.</p><h2 id="控糖-控的是添加糖">控糖,控的是 “添加糖”</h2><p> 糖类是人体必须的三大营养物质之一,应该均衡地摄入.<strong>真正需要限制摄入的是 “添加糖”(游离糖)</strong>:</p><p> ①添加在加工食品中的白糖、冰糖、红糖、黑糖.它们的主要成分都是蔗糖,加工原料均为甘蔗或甜菜,只是加工工艺不同.</p><p> ②各种添加了果葡糖浆、葡萄糖浆、麦芽糖浆、淀粉糖浆的含糖饮品.</p><p> ③水果汁和蜂蜜也属于要限制的糖类.水果榨汁过程中会损失大量膳食纤维,消化吸收会加快;蜂蜜主要是果糖和葡萄糖,属于应该控制的糖类.</p><p> 世界卫生组织建议要终生控制游离糖摄入,但是现实中又很难做到完全不吃。所以,我们最好将每天的游离糖摄入量控制在 25g 以内.</p><h3 id="代糖-也别吃过量">代糖,也别吃过量</h3><p> 现在不少商家会选择用糖醇或人工甜味剂替代添加糖,不牺牲风味的同时,实现限糖.</p><ol type="1"><li>糖醇</li></ol><p> 糖醇养型合成甜味剂,我们在配料表中看到的赤藓糖醇、山梨糖醇、麦芽糖醇、甘露醇、木糖醇等配料,就是糖醇家族的成员,优势也非常明显:</p><p> ①提供甜味的同时,提供的热量大多远低于蔗糖;</p><p> ②摄入后不会引起血糖大幅度升高;</p><p> ③在口腔中也不受微生物作用,不会引起龋齿.</p><ol start="2" type="1"><li>人工甜味剂</li></ol><p> 人工甜味剂属于非营养型甜味剂,我们在配料表中看到的糖精、安赛蜜、阿斯巴甜等配料就属于这个类别.</p><p> 和糖醇一样,人工甜味剂也能在一定程度上帮助人们降低热量和糖分的摄入,但是它绝不是放心之选 —— 其能起打开食欲的作用,在心理上反而会对那些又甜、又实际存在热量的食物产生更强烈的依赖,这样一来可能会间接促成食物和能量摄入超标的结局.</p><p> 总的来说,不管是糖醇还是人工甜味剂,日常可以以少量、低频次的节奏去摄入,但不能毫无节制的食用.</p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>让人上瘾,又伤心、伤脑…… 这味调料家家都有,但劝你别多吃!</p>
<p>2022-03-01 14:00 来源: CCTV 回家吃饭</p>
<p> 糖果、冰激凌、蛋糕、饼干、巧克力…… 甜食让不少人欲罢不能,
情绪不好时来一口,感觉整个世界都明媚了;时下的网红饮品奶茶,
更是被戏称为 “肥宅快乐水”, 深受年轻人的喜爱~</p>
<p> 殊不知,大快朵颐的同时,甜食更像是一位隐形的 “甜蜜杀手”,
不仅会让人慢慢 “上瘾”, 还会悄悄摧毁着你的身体!</p></summary>
<category term="生活" scheme="https://fetasty.github.io/categories/life/"/>
</entry>
<entry>
<title>dumpbin 查看 DLL 导出信息</title>
<link href="https://fetasty.github.io/posts/e6310a89/"/>
<id>https://fetasty.github.io/posts/e6310a89/</id>
<published>2022-02-22T13:17:40.000Z</published>
<updated>2023-06-19T08:48:51.670Z</updated>
<content type="html"><![CDATA[<p>dumpbin 是 vs 提供的一个工具,可以用于查看 dll/exe 的信息,32 位还是 64 位,导出函数等</p><span id="more"></span><p><a href="https://blog.csdn.net/luoyu510183/article/details/93666808">https://blog.csdn.net/luoyu510183/article/details/93666808</a></p><p>如果导入 dll 时发现没有找到该函数,要根据 dll 的导出约定方式设置对应的导入方式,否则虽然函数名一样但实际上符号是不同的.</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dumpbin /exports xxx.dll</span><br></pre></td></tr></tbody></table></figure><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> {</span><br><span class="line"> <span class="comment">//extern "C" + _stdcall,函数导出符号为 _CreateNativeManager@0 : _+函数名+@+传参字节数</span></span><br><span class="line"> <span class="comment">//由于_stdcall是被调用方清理堆栈, 所以函数符号里面包含了传参的信息</span></span><br><span class="line"> _declspec(dllexport) <span class="function">NativeManager* _stdcall <span class="title">CreateNativeManager</span><span class="params">()</span></span>;</span><br><span class="line"> _declspec(dllexport) <span class="function"><span class="type">void</span> _stdcall <span class="title">ReleaseNativeManager</span><span class="params">()</span></span>;</span><br><span class="line"> _declspec(dllexport) <span class="built_in">void</span>(_stdcall ExSetLogHandler)(LogHandler handler);</span><br><span class="line"> <span class="comment">//extern "C" + _cdecl,函数导出符号为 ReleaseNativeManager2 : 函数名</span></span><br><span class="line"> <span class="comment">//由于_cdecl是调用方清理堆栈, 所以只需要函数名就可以</span></span><br><span class="line"> _declspec(dllexport) <span class="built_in">void</span>(_cdecl ReleaseNativeManager2)();</span><br><span class="line">}</span><br><span class="line"><span class="comment">//不使用extern的情况下, 是C++的导出方式, 函数符号如下:</span></span><br><span class="line"><span class="comment">//?ReleaseNativeManager1@@YGXH@Z : ?+函数名+@@YG+返回类型+参数1类型...+@Z</span></span><br><span class="line"><span class="comment">//如果是_cdecl @YG变为@YA</span></span><br><span class="line"><span class="comment">//如果没有参数即参数为void,则以Z结尾, 例如:</span></span><br><span class="line"><span class="comment">//?ReleaseNativeManager3@@YAXXZ : ?+函数名+@@YA+返回类型+XZ</span></span><br><span class="line"><span class="comment">//以上 X表示 void类型, H表示int参数类型</span></span><br><span class="line">_declspec(dllexport) <span class="built_in">void</span>(_stdcall ReleaseNativeManager1)(<span class="type">int</span> num);</span><br><span class="line">_declspec(dllexport) <span class="built_in">void</span>(_cdecl ReleaseNativeManager3)();</span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>dumpbin 是 vs 提供的一个工具,可以用于查看 dll/exe 的信息,32 位还是 64 位,
导出函数等</p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
<category term="DLL" scheme="https://fetasty.github.io/tags/DLL/"/>
</entry>
<entry>
<title>Python 中的可变对象与不可变对象</title>
<link href="https://fetasty.github.io/posts/c3f5fb77/"/>
<id>https://fetasty.github.io/posts/c3f5fb77/</id>
<published>2022-02-21T12:18:46.000Z</published>
<updated>2023-06-19T06:55:27.939Z</updated>
<content type="html"><![CDATA[<p>Python 中只存在 “引用传递” 这一种传递方式,准确来说应该是<strong>指针传递</strong> ,通过 <code>id()</code> 函数可以确定,参数传入前和传入后的地址值一样</p><p>所谓的对象可变与不可变,其实是看是否提供了修改自身对象的方法</p><span id="more"></span><p><strong>变量无类型,对象有类型</strong></p><p>不可变 (immutable) 对象类型 (指针地址不可变)</p><ul><li>int</li><li>float</li><li>decimal</li><li>complex</li><li>bool</li><li>str</li><li>tuple</li><li>range</li><li>frozenset</li><li>bytes</li></ul><p>可变 (mutable) 对象类型</p><ul><li>list</li><li>dict</li><li>set</li><li>bytearray</li></ul><p>user-defined classes (unless specifically made immutable)</p><p>Python 中的对象类型分为 <strong>可变类型</strong> 和<strong>不可变类型</strong></p><p>例如: Python 中的数字是不可变类型</p><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">a = <span class="number">2</span> <span class="comment"># 变量 a 指向一个 Number 对象</span></span><br><span class="line">b = <span class="number">2</span> <span class="comment"># 变量 b 和 a 指向同一个 Number 对象 此时 id(a) == id(b)</span></span><br><span class="line">a = <span class="number">1</span> <span class="comment"># 变量 a 指向一个新的 Number 对象, 而并不是 a 原本指向的 Number 对象发生了改变! 此时 id(a) != id(b)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 同样, 函数参数传递时也是如此</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">num</span>):</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(num)) <span class="comment"># 第一次打印的 id 是与外部的参数的 id 一致 (引用传递, 准确来说是指针传递)</span></span><br><span class="line"> num += <span class="number">2</span> <span class="comment"># 改变了 num 指向的对象, id(num) 发生了改变, 但不影响外部传入变量的地址</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(num))</span><br><span class="line"></span><br><span class="line">add(a) <span class="comment"># 传递变量 a 其实是“引用传递”, 也就是将 a 指向的内存地址传递了</span></span><br></pre></td></tr></tbody></table></figure><p>即使对于可变类型,其实也是<strong>指针传递</strong></p><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">test</span>(<span class="params">lst</span>):</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(lst)) <span class="comment"># 2263872110464</span></span><br><span class="line"> lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(lst)) <span class="comment"># 2263872133184</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> l = [<span class="number">9</span>, <span class="number">8</span>, <span class="number">7</span>]</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(l)) <span class="comment"># 2263872110464</span></span><br><span class="line"> <span class="built_in">print</span>(l) <span class="comment"># [9, 8, 7]</span></span><br><span class="line"> test(l) <span class="comment"># 函数中改变的</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(l)) <span class="comment"># 2263872110464</span></span><br><span class="line"> <span class="built_in">print</span>(l) <span class="comment"># [9, 8, 7]</span></span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure><p>可变类型的 "可变", 体现在下面这种情况</p><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">test</span>(<span class="params">lst</span>):</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(lst)) <span class="comment"># 2389391376256</span></span><br><span class="line"> lst.append(<span class="number">33</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(lst)) <span class="comment"># 2389391376256</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> l = [<span class="number">9</span>, <span class="number">8</span>, <span class="number">7</span>]</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(l)) <span class="comment"># 2389391376256</span></span><br><span class="line"> <span class="built_in">print</span>(l) <span class="comment"># [9, 8, 7]</span></span><br><span class="line"> test(l)</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">id</span>(l)) <span class="comment"># 2389391376256</span></span><br><span class="line"> <span class="built_in">print</span>(l) <span class="comment"># [9, 8, 7, 33]</span></span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure><p>参考文章:</p><p><a href="https://www.cnblogs.com/shiyublog/p/10809953.html">https://www.cnblogs.com/shiyublog/p/10809953.html</a></p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>Python 中只存在 “引用传递” 这一种传递方式,
准确来说应该是<strong>指针传递</strong> ,
通过 <code>id()</code> 函数可以确定,参数传入前和传入后的地址值一样</p>
<p>所谓的对象可变与不可变,其实是看是否提供了修改自身对象的方法</p></summary>
<category term="Python" scheme="https://fetasty.github.io/categories/Python/"/>
<category term="Python" scheme="https://fetasty.github.io/tags/Python/"/>
</entry>
<entry>
<title>Python 临时改变 Path 搜索目录</title>
<link href="https://fetasty.github.io/posts/285687f/"/>
<id>https://fetasty.github.io/posts/285687f/</id>
<published>2022-02-21T12:17:24.000Z</published>
<updated>2023-06-19T06:55:27.939Z</updated>
<content type="html"><![CDATA[<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sys</span><br><span class="line">sys.path.append(<span class="string">r".\lib"</span>)</span><br><span class="line"><span class="keyword">import</span> mymodule <span class="comment"># lib目录下的自定义模块</span></span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><sp</summary>
<category term="Python" scheme="https://fetasty.github.io/categories/Python/"/>
</entry>
<entry>
<title>Python 处理 C 语言结构</title>
<link href="https://fetasty.github.io/posts/669ef2f3/"/>
<id>https://fetasty.github.io/posts/669ef2f3/</id>
<published>2022-02-21T12:15:43.000Z</published>
<updated>2023-06-19T06:55:27.940Z</updated>
<content type="html"><![CDATA[<p>Python 可以高效率开发,但涉及到运算密集部分,还是应该交给 C/C++,这里就涉及到数据交互的结构与格式问题</p><span id="more"></span><p>//todo 不够详细,例子不具体,内存布局与解析没讲明白</p><figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"><span class="keyword">from</span> ctypes <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyStruct</span>(<span class="title class_ inherited__">Structure</span>):</span><br><span class="line"> _fields_ = [</span><br><span class="line"> (<span class="string">"v1"</span>, c_char), <span class="comment"># c_byte</span></span><br><span class="line"> (<span class="string">"v2"</span>, c_char), <span class="comment"># c_byte</span></span><br><span class="line"> (<span class="string">"v1_dire"</span>, c_char), <span class="comment"># c_byte</span></span><br><span class="line"> (<span class="string">"v2_dire"</span>, c_char) <span class="comment"># c_byte</span></span><br><span class="line"> ]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">mys = MyStruct()</span><br><span class="line">mys.v1 = <span class="number">20</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">type</span>(mys.v1))</span><br><span class="line">mys.v2 = <span class="number">30</span></span><br><span class="line">mys.v1_dire = <span class="number">0</span></span><br><span class="line">mys.v2_dire = <span class="number">0</span></span><br><span class="line">msg = struct.pack(<span class="string">'cccc'</span>, mys.v1, mys.v2, mys.v1_dire, mys.v2_dire) <span class="comment"># BBBB</span></span><br><span class="line"><span class="built_in">print</span>(msg)</span><br><span class="line">ss = struct.unpack(<span class="string">'cccc'</span>, msg) <span class="comment"># BBBB</span></span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>Python 可以高效率开发,但涉及到运算密集部分,还是应该交给 C/C++,
这里就涉及到数据交互的结构与格式问题</p></summary>
<category term="Python" scheme="https://fetasty.github.io/categories/Python/"/>
</entry>
<entry>
<title>C++ 中 new-delete 与 malloc-free 的比较</title>
<link href="https://fetasty.github.io/posts/f8def853/"/>
<id>https://fetasty.github.io/posts/f8def853/</id>
<published>2022-02-20T14:36:32.000Z</published>
<updated>2023-06-19T08:50:26.788Z</updated>
<content type="html"><![CDATA[<p>new-delete 与 malloc-free</p><span id="more"></span><h2 id="newdelete-与-mallocfree-的比较">new&delete 与malloc&free 的比较</h2><ul><li><code>malloc/free</code> 是 C 语言的库函数</li><li><code>new/delete</code> <code>new[]/delete[]</code> 是 C++中的运算符</li><li><code>malloc/free</code> 只是申请内存空间,释放空间</li><li><code>new/delete</code> 不仅会申请内存空间,还会根据类型初始化内存空间,this 指针绑定,调用构造函数和析构函数进行初始化或者清理等操作</li></ul><p>这里有两张网上找到的图</p><ol type="1"><li><p><code>new/delete</code> 实现 <img data-src="/posts/f8def853/new_delete%E5%AE%9E%E7%8E%B0.png" class=""></p></li><li><p><code>new[]/delete[]</code> 实现</p><img data-src="/posts/f8def853/new_delete%E6%95%B0%E7%BB%84%E5%AE%9E%E7%8E%B0.png" class=""></li></ol><p>不一定完全正确,但具有一定参考意义,<code>new[]</code> 文中说会多申请4 字节 空间,在开始位置存储对象个数,这里我在 64 位 编译环境下验证了一下,是前 8 字节 空间中存储的,应该与系统位数有关</p><p>测试环境: Win10 64 bit & GCC 8.1.0 64 bit</p><p>这里定义一个 Test 类作测试</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Test</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> index;</span><br><span class="line"> <span class="built_in">Test</span>()</span><br><span class="line"> {</span><br><span class="line"> x = ++index;</span><br><span class="line"> str = str + std::<span class="built_in">to_string</span>(x);</span><br><span class="line"> std::cout << <span class="string">"Test Constructor() this="</span> << <span class="keyword">this</span> << std::endl;</span><br><span class="line"> }</span><br><span class="line"> ~<span class="built_in">Test</span>()</span><br><span class="line"> {</span><br><span class="line"> std::cout << <span class="string">"Test Destructor() this="</span> << <span class="keyword">this</span> << std::endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Show</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> std::cout << <span class="string">"Test show x("</span> << x << <span class="string">"), str("</span> << str << <span class="string">")"</span> << std::endl;</span><br><span class="line"> }</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="type">int</span> x;</span><br><span class="line"> std::string str {<span class="string">"sssaaa"</span>};</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> Test::index = <span class="number">0</span>;</span><br></pre></td></tr></tbody></table></figure><p>测试:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span>, <span class="type">char</span>**)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="type">int</span> size = <span class="built_in">sizeof</span>(Test);</span><br><span class="line"> Test* p = <span class="keyword">new</span> Test[<span class="number">3</span>]();</span><br><span class="line"> <span class="type">uint64_t</span>* sp = (<span class="type">uint64_t</span>*)p - <span class="number">1</span>;</span><br><span class="line"> std::cout << <span class="string">"Test obj size: "</span> << *sp << std::endl;</span><br><span class="line"> <span class="keyword">delete</span>[] p;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>输出如下</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Test Constructor() this=0x1d1e88</span><br><span class="line">Test Constructor() this=0x1d1eb0</span><br><span class="line">Test Constructor() this=0x1d1ed8</span><br><span class="line">Test obj size: 3</span><br><span class="line">Test Destructor() this=0x1d1ed8</span><br><span class="line">Test Destructor() this=0x1d1eb0</span><br><span class="line">Test Destructor() this=0x1d1e88</span><br></pre></td></tr></tbody></table></figure><p>如果我们修改一下上面的测试代码,更改一下前面的对象个数</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span>, <span class="type">char</span>**)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="type">int</span> size = <span class="built_in">sizeof</span>(Test);</span><br><span class="line"> Test* p = <span class="keyword">new</span> Test[<span class="number">3</span>]();</span><br><span class="line"> <span class="type">uint64_t</span>* sp = (<span class="type">uint64_t</span>*)p - <span class="number">1</span>;</span><br><span class="line"> std::cout << <span class="string">"Test obj size: "</span> << *sp << std::endl;</span><br><span class="line"> *sp = <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">delete</span>[] p;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>运行结果如下</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Test Constructor() this=0x6e1e88</span><br><span class="line">Test Constructor() this=0x6e1eb0</span><br><span class="line">Test Constructor() this=0x6e1ed8</span><br><span class="line">Test obj size: 3</span><br><span class="line">Test Destructor() this=0x6e1eb0</span><br><span class="line">Test Destructor() this=0x6e1e88</span><br></pre></td></tr></tbody></table></figure><p><code>delete[]</code> 只执行了两次析构</p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>new-delete 与 malloc-free</p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>C++ 中使用 fstream 一次读取整个文件内容</title>
<link href="https://fetasty.github.io/posts/3579021f/"/>
<id>https://fetasty.github.io/posts/3579021f/</id>
<published>2022-02-20T14:33:41.000Z</published>
<updated>2023-06-19T08:50:23.272Z</updated>
<content type="html"><![CDATA[<p>原文地址 <a href="https://www.cnblogs.com/kex1n/p/4028428.html">https://www.cnblogs.com/kex1n/p/4028428.html</a></p><span id="more"></span><h2 id="读取到-char">读取到 char*</h2><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">std::ifstream t; <span class="type">int</span> length; t.<span class="built_in">open</span>(<span class="string">"file.txt"</span>); <span class="comment">// open input file</span></span><br><span class="line">t.<span class="built_in">seekg</span>(<span class="number">0</span>, std::ios::end); <span class="comment">// go to the end</span></span><br><span class="line">length = t.<span class="built_in">tellg</span>(); <span class="comment">// report location (this is the length)</span></span><br><span class="line">t.<span class="built_in">seekg</span>(<span class="number">0</span>, std::ios::beg); <span class="comment">// go back to the beginning</span></span><br><span class="line">buffer = <span class="keyword">new</span> <span class="type">char</span>[length]; <span class="comment">// allocate memory for a buffer of appropriate dimension</span></span><br><span class="line">t.<span class="built_in">read</span>(buffer, length); <span class="comment">// read the whole file into the buffer</span></span><br><span class="line">t.<span class="built_in">close</span>(); <span class="comment">// close file handle</span></span><br><span class="line"><span class="comment">// ... do stuff with buffer here ...</span></span><br></pre></td></tr></tbody></table></figure><h2 id="读取到-stdstring">读取到 std::string</h2><p>方法一</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><fstream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><streambuf></span></span></span><br><span class="line"><span class="function">std::ifstream <span class="title">t</span><span class="params">(<span class="string">"file.txt"</span>)</span></span>;</span><br><span class="line"><span class="function">std::string <span class="title">str</span><span class="params">((std::istreambuf_iterator<<span class="type">char</span>>(t)), std::istreambuf_iterator<<span class="type">char</span>>())</span></span>;</span><br></pre></td></tr></tbody></table></figure><p>方法二</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><fstream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sstream></span></span></span><br><span class="line"><span class="function">std::ifstream <span class="title">t</span><span class="params">(<span class="string">"file.txt"</span>)</span></span>;</span><br><span class="line">std::stringstream buffer;</span><br><span class="line">buffer << t.<span class="built_in">rdbuf</span>();</span><br><span class="line"><span class="function">std::string <span class="title">contents</span><span class="params">(buffer.str())</span></span>;</span><br></pre></td></tr></tbody></table></figure><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>原文地址 <a href="https://www.cnblogs.com/kex1n/p/4028428.html">https://www.cnblogs.com/kex1n/p/4028428.html</a></p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>C++ 中 lambda 使用注意事项</title>
<link href="https://fetasty.github.io/posts/24017eff/"/>
<id>https://fetasty.github.io/posts/24017eff/</id>
<published>2022-02-20T14:32:43.000Z</published>
<updated>2023-06-19T08:50:31.164Z</updated>
<content type="html"><![CDATA[<p><a href="https://blog.csdn.net/czyt1988/article/details/80149695">https://blog.csdn.net/czyt1988/article/details/80149695</a></p><ul><li><strong> 不要使用 lambda 以引用方式捕获局部变量</strong>!!!(悬挂引用)</li><li>lambda 捕获 this 时也需要注意,lambda 的调用时机是否在 this 的生命周期之外(类生命周期)</li></ul><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p><a href="https://blog.csdn.net/czyt1988/article/details/80149695">https://blog.csdn.net/czyt1988/article/details/80149695</a></p>
<ul>
<l</summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>C++ 中的 move 和 forward</title>
<link href="https://fetasty.github.io/posts/be74f994/"/>
<id>https://fetasty.github.io/posts/be74f994/</id>
<published>2022-02-20T14:31:12.000Z</published>
<updated>2023-06-19T08:50:11.139Z</updated>
<content type="html"><![CDATA[<p>std::move 和 std::forward 仅仅是进行类型转换的函数(实际上是函数模板).std::move 无条件的将其参数转换为右值,而 std::forward 只在必要情况下进行这个转换,就是这样.</p><span id="more"></span><ol type="1"><li>std::move 执行一个无条件的转化到右值。它本身并不移动任何东西;</li><li>std::forward 把其参数转换为右值,仅仅在那个参数被绑定到一个右值时;</li><li>std::move 和 std::forward 在运行时(runtime)都不做任何事.</li></ol><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>std::move 和 std::forward 仅仅是进行类型转换的函数(实际上是函数模板).
std::move 无条件的将其参数转换为右值,
而 std::forward 只在必要情况下进行这个转换,就是这样.</p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>C++ 数组长度可以为变量吗</title>
<link href="https://fetasty.github.io/posts/7a9ccc43/"/>
<id>https://fetasty.github.io/posts/7a9ccc43/</id>
<published>2022-02-20T14:28:39.000Z</published>
<updated>2023-06-19T08:51:09.763Z</updated>
<content type="html"><![CDATA[<p>转载:原创程序喵大人 程序喵大人 (微信公众号) (收录于话题:C++ 精进之路)</p><p>推荐一下这个专题,讲 C++ 很棒</p><span id="more"></span><h2 id="c数组长度可以为变量吗">C++ 数组长度可以为变量吗?</h2><p>37 个</p><p>大家好,我是喵大人,今天跟大家分享的是关于 C++ 数组提出几点问题:</p><h3 id="预备">预备</h3><p>先看下这两段代码,并思考如下问题.</p><p>1、变量作为数组的长度可行吗?</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(<span class="type">int</span> num)</span> </span>{</span><br><span class="line"> <span class="type">int</span> array[num]; <span class="comment">// num > 0</span></span><br><span class="line"> cout << <span class="string">"num "</span> << num << endl;</span><br><span class="line"> cout << <span class="string">"sizeof array "</span> << <span class="built_in">sizeof</span>(array) << endl;</span><br><span class="line"> array[<span class="number">0</span>] = <span class="number">20</span>;</span><br><span class="line"> cout << <span class="string">"array[0] "</span> << array[<span class="number">0</span>] << endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">func</span>(<span class="number">6</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>输出:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">num <span class="number">6</span></span><br><span class="line"><span class="keyword">sizeof</span> array <span class="number">24</span></span><br><span class="line">array[<span class="number">0</span>] <span class="number">20</span></span><br></pre></td></tr></tbody></table></figure><p>2、访问超过长度的数组下标的值会发生什么?</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> array[<span class="number">10</span>];</span><br><span class="line"> array[<span class="number">3</span>] = <span class="number">1</span>;</span><br><span class="line"> array[<span class="number">20</span>] = <span class="number">3</span>;</span><br><span class="line"> cout << <span class="string">"sizeof array "</span> << <span class="built_in">sizeof</span>(array) << endl;</span><br><span class="line"> cout << <span class="string">"array[3] "</span> << array[<span class="number">3</span>] << endl;</span><br><span class="line"> cout << <span class="string">"array[20] "</span> << array[<span class="number">20</span>] << endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">func</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>输出:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">sizeof</span> array <span class="number">40</span></span><br><span class="line">array[<span class="number">3</span>] <span class="number">1</span></span><br><span class="line">array[<span class="number">20</span>] <span class="number">3</span></span><br></pre></td></tr></tbody></table></figure><h3 id="分析">分析</h3><p><strong>首先分析问题 1</strong>,我们平时看书学习过程中总看见说 C++ 的数组长度一定要是常量且不能是变量,很多资料需要在编译期确定栈帧的大小,如果是变量就不能在编译器确定栈帧大小,但上述代码为什么可以正常运行呢?光看不如实践,先看这样一段代码:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func2</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> a;</span><br><span class="line"> <span class="type">int</span> b[<span class="number">4</span>];</span><br><span class="line"> <span class="type">int</span> c;</span><br><span class="line"> cout << <span class="string">"func2a address "</span> << &a << endl;</span><br><span class="line"> cout << <span class="string">"func2b address "</span> << &b << endl;</span><br><span class="line"> cout << <span class="string">"func2c address "</span> << &c << endl;</span><br><span class="line"> <span class="comment">// func1();</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func3</span><span class="params">(<span class="type">int</span> num)</span> </span>{</span><br><span class="line"> <span class="type">int</span> a;</span><br><span class="line"> <span class="type">int</span> b[<span class="number">4</span>];</span><br><span class="line"> <span class="type">int</span> c;</span><br><span class="line"> cout << <span class="string">"func3a address "</span> << &a << endl;</span><br><span class="line"> cout << <span class="string">"func3b address "</span> << &b << endl;</span><br><span class="line"> cout << <span class="string">"func3c address "</span> << &c << endl;</span><br><span class="line"> <span class="built_in">func2</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func4</span><span class="params">(<span class="type">int</span> num)</span> </span>{</span><br><span class="line"> <span class="type">int</span> a;</span><br><span class="line"> <span class="type">int</span> b[<span class="number">4</span>];</span><br><span class="line"> <span class="type">int</span> c;</span><br><span class="line"> cout << <span class="string">"func4a address "</span> << &a << endl;</span><br><span class="line"> cout << <span class="string">"func4b address "</span> << &b << endl;</span><br><span class="line"> cout << <span class="string">"func4c address "</span> << &c << endl;</span><br><span class="line"> <span class="built_in">func3</span>(num);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">func4</span>(<span class="number">5</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>输出:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">func4a address <span class="number">0x7ffeb675f418</span></span><br><span class="line">func4b address <span class="number">0x7ffeb675f420</span></span><br><span class="line">func4c address <span class="number">0x7ffeb675f41c</span></span><br><span class="line">func3a address <span class="number">0x7ffeb675f3c8</span></span><br><span class="line">func3b address <span class="number">0x7ffeb675f3d0</span></span><br><span class="line">func3c address <span class="number">0x7ffeb675f3cc</span></span><br><span class="line">func2a address <span class="number">0x7ffeb675f378</span></span><br><span class="line">func2b address <span class="number">0x7ffeb675f380</span></span><br><span class="line">func2c address <span class="number">0x7ffeb675f37c</span></span><br></pre></td></tr></tbody></table></figure><p>再看这段代码:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">func2</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> a;</span><br><span class="line"> <span class="type">int</span> b[<span class="number">4</span>];</span><br><span class="line"> <span class="type">int</span> c;</span><br><span class="line"> cout << <span class="string">"func2a address "</span> << &a << endl;</span><br><span class="line"> cout << <span class="string">"func2b address "</span> << &b << endl;</span><br><span class="line"> cout << <span class="string">"func2c address "</span> << &c << endl;</span><br><span class="line"> <span class="comment">// func1();</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func3</span><span class="params">(<span class="type">int</span> num)</span> </span>{</span><br><span class="line"> <span class="type">int</span> a;</span><br><span class="line"> <span class="type">int</span> b[num];</span><br><span class="line"> <span class="type">int</span> c;</span><br><span class="line"> cout << <span class="string">"func3a address "</span> << &a << endl;</span><br><span class="line"> cout << <span class="string">"func3b address "</span> << &b << endl;</span><br><span class="line"> cout << <span class="string">"func3c address "</span> << &c << endl;</span><br><span class="line"> <span class="built_in">func2</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func4</span><span class="params">(<span class="type">int</span> num)</span> </span>{</span><br><span class="line"> <span class="type">int</span> a;</span><br><span class="line"> <span class="type">int</span> b[<span class="number">4</span>];</span><br><span class="line"> <span class="type">int</span> c;</span><br><span class="line"> cout << <span class="string">"func4a address "</span> << &a << endl;</span><br><span class="line"> cout << <span class="string">"func4b address "</span> << &b << endl;</span><br><span class="line"> cout << <span class="string">"func4c address "</span> << &c << endl;</span><br><span class="line"> <span class="built_in">func3</span>(num);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">func4</span>(<span class="number">100</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>输出:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">func4a address <span class="number">0x7ffff2c76568</span></span><br><span class="line">func4b address <span class="number">0x7ffff2c76570</span></span><br><span class="line">func4c address <span class="number">0x7ffff2c7656c</span></span><br><span class="line">func3a address <span class="number">0x7ffff2c76510</span></span><br><span class="line">func3b address <span class="number">0x7ffff2c76360</span></span><br><span class="line">func3c address <span class="number">0x7ffff2c76514</span></span><br><span class="line">func2a address <span class="number">0x7ffff2c76328</span></span><br><span class="line">func2b address <span class="number">0x7ffff2c76330</span></span><br><span class="line">func2c address <span class="number">0x7ffff2c7632c</span></span><br></pre></td></tr></tbody></table></figure><p>func4a - func3a = 88</p><p>func3a - func2a = 488</p><p>从上面两段代码其实可以看出 C++ 是支持变量长度的数组的,说不支持的那是很古老的编译器,在如下链接中也可以找到答案.</p><p><a href="https://c-for-dummies.com/blog/?p=3488">https://c-for-dummies.com/blog/?p=3488</a></p><p><a href="https://www.drdobbs.com/the-new-cwhy-variable-length-arrays/184401444">https://www.drdobbs.com/the-new-cwhy-variable-length-arrays/184401444</a></p><p><a href="https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard">https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard</a></p><p>备注:尽管 C++ 目前支持变量长度的数组,但是不建议使用,因为数组使用的是栈内存,栈内存是有大小限制的,一般是 8192 字节,既然长度是变量,那就可能是任何值,就有可能超过 8192, 这样就会 stackoverflow, 所以动态内存最好使用堆内存.</p><p><strong>再分析问题 2:操作超过数组长度的内存会发生什么?</strong></p><p>看下面这段代码:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> array[<span class="number">10</span>];</span><br><span class="line"> array[<span class="number">3</span>] = <span class="number">1</span>;</span><br><span class="line"> array[<span class="number">40</span>] = <span class="number">3</span>;</span><br><span class="line"> cout << <span class="string">"sizeof array "</span> << <span class="built_in">sizeof</span>(array) << endl;</span><br><span class="line"> cout << <span class="string">"array[3] "</span> << array[<span class="number">3</span>] << endl;</span><br><span class="line"> cout << <span class="string">"array[40] "</span> << array[<span class="number">40</span>] << endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> a[<span class="number">200</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">200</span>; ++i) {</span><br><span class="line"> a[i] = <span class="number">100</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">200</span>; ++i) {</span><br><span class="line"> cout << a[i] << <span class="string">" "</span>;</span><br><span class="line"> }</span><br><span class="line"> cout << endl << <span class="string">"====================="</span> << endl;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">func</span>();</span><br><span class="line"> cout << <span class="string">"====================="</span> << endl;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">200</span>; ++i) {</span><br><span class="line"> cout << a[i] << <span class="string">" "</span>;</span><br><span class="line"> }</span><br><span class="line"> cout << endl << <span class="string">"====================="</span> << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>输出:</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">root@<span class="number">3</span>eaa9392a3d9:/ubuntu/test_dir# ./a.out</span><br><span class="line"><span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span></span><br><span class="line">=====================</span><br><span class="line"><span class="keyword">sizeof</span> array <span class="number">40</span></span><br><span class="line">array[<span class="number">3</span>] <span class="number">1</span></span><br><span class="line">array[<span class="number">40</span>] <span class="number">3</span></span><br><span class="line">=====================</span><br><span class="line"><span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">3</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span> <span class="number">100</span></span><br><span class="line">=====================</span><br></pre></td></tr></tbody></table></figure><p>看代码输出,在函数内操作超过数组长度的内存没有什么影响,但是它却导致了上一级的数组 a [200] 里的内容被改变,因为数组使用的是栈内存,经过问题 1 的代码输出以及分析可以看出,栈帧内存是向下增长的,代码中操作了超过数组长度的内存地址,就影响到了之前栈帧的内存数据,导致之前栈内存数据出现错误,可能就会引发大 bug.</p><blockquote><p><strong>总结</strong></p></blockquote><p><strong>summary</strong></p><p>C++ 中数组长度可以是变量,但是不建议使用,因为数组使用的是栈内存,变量可以是个比较大的数,这样会导致 stack overflow, 建议使用堆内存.</p><p>操作超过数组长度的内存可以编译通过且表面上看不出来问题,但是会导致栈内存出现脏写,最终可能会引发难以排查的 bug,建议数组使用 std::array,操作超过长度的下标会抛异常有利于开发者及时发现错误.</p><p>▼</p><p>更多精彩推荐,请关注我们</p><p>▼</p><p><strong>代码精进之路 </strong></p><p>代码精进之路,我们一起成长!</p><p><img src="https://secure2.wostatic.cn/static/wtedawzen2SaSyA4ZQ87yB/image.png"></p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>转载:原创程序喵大人 程序喵大人 (微信公众号) (收录于话题:
C++ 精进之路)</p>
<p>推荐一下这个专题,讲 C++ 很棒</p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
<entry>
<title>C++ 中使用智能指针管理数组</title>
<link href="https://fetasty.github.io/posts/21ebbed9/"/>
<id>https://fetasty.github.io/posts/21ebbed9/</id>
<published>2022-02-20T14:27:59.000Z</published>
<updated>2023-06-19T08:50:18.902Z</updated>
<content type="html"><![CDATA[<p>C++ 智能指针不仅能管理普通对象,也可以管理数组对象</p><span id="more"></span><p>以前只知道使用智能指针管理对象</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr<A> <span class="title">pA</span><span class="params">(<span class="keyword">new</span> A)</span></span>;</span><br><span class="line"><span class="comment">// do something with pA or pA.Get()</span></span><br><span class="line"><span class="comment">// 超过作用域后, pA自动释放资源</span></span><br></pre></td></tr></tbody></table></figure><p>智能指针也可以用于管理数组</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">std::unique_ptr<<span class="type">int</span>[]> pArr;</span><br><span class="line">pArr.<span class="built_in">reset</span>(<span class="keyword">new</span> <span class="type">int</span>[<span class="number">10</span>]); <span class="comment">// pArr 管理10个大小的int数组</span></span><br><span class="line">pArr.<span class="built_in">reset</span>(<span class="keyword">new</span> <span class="type">int</span>[<span class="number">64</span>]); <span class="comment">// 替换pArr的管理数组, 原来的10大小的数组将被自动释放</span></span><br></pre></td></tr></tbody></table></figure><p>以上代码管理数组对象的 <code>reset</code> 方法在 C++17 之前不可用</p><figure class="highlight c++"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 特化 unique_ptr<T[]>的成员</span></span><br><span class="line"><span class="function"><span class="keyword">template</span><<span class="keyword">class</span> U></span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">reset</span><span class="params">(U)</span> </span>= <span class="keyword">delete</span>; <span class="comment">// C++17 前</span></span><br><span class="line"><span class="function"><span class="keyword">template</span><<span class="keyword">class</span> U></span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">reset</span><span class="params">(U)</span> <span class="keyword">noexcept</span></span>; <span class="comment">// C++17 起</span></span><br></pre></td></tr></tbody></table></figure><p>千万不要用普通的智能指针指向数组地址,否则可能内存泄漏!!</p><p><del><code>std::unique_ptr<int> p(new int[xx])</code></del>错误用法!</p><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kity.min.js"></script><script type="text/javascript" src="https://unpkg.com/[email protected]/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://unpkg.com/[email protected]/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/mindmap.min.css">]]></content>
<summary type="html"><p>C++ 智能指针不仅能管理普通对象,也可以管理数组对象</p></summary>
<category term="C++" scheme="https://fetasty.github.io/categories/C/"/>
<category term="C++" scheme="https://fetasty.github.io/tags/C/"/>
</entry>
</feed>