CPython3.7.9源碼學習一:C語言基礎、整數對象

C 語言基礎

結構體

// 
struct(關鍵字) 名稱 {結構體成員};// 定義結構體
struct Student {  char name[50];  int age;  float score;  
};// 初始化 結構體變量
struct Student stu1;
strcpy(stu1.name, "張三");  
stu1.age = 20;  
stu1.score = 90.5;// 初始化 結構體數組
struct Student students[2];  strcpy(students[0].name, "張三");  
students[0].age = 20;  
students[0].score = 90.5;  strcpy(students[1].name, "李四");  
students[1].age = 21;  
students[1].score = 85.0;  // 結構體指針,訪問結構體成員
struct Student *ptr = &stu1;  
printf("學生名字: %s\n", ptr->name);  
printf("學生年齡: %d\n", ptr->age);  
printf("學生分數: %.1f\n", ptr->score);// cpython中的結構體,長整型的結構體
struct _longobject {PyObject_VAR_HEADdigit ob_digit[1];
};

typedef

// 用于給數據類型定義別名,常用于給結構體定義別名// 將int別名設置成integer
typedef int integer;  
// 將int的指針設置pinteger
typedef int* pinteger;  // 定義變量
integer a = 100;
pinteger pa = &a;struct Student {  char name[50];  int age;  float score;  
};// 為struct Student 設置一個別名為stu 
typedef struct Student stu; 
// 為struct Student* 設置一個別名為pstu 
typedef struct Student* pstu;  
stu stu1;
stu1.name = "張三";
stu1.age = 20;
stu1.score = 89.5;pstu stu2 = (pstu)malloc(sizeof(Student)); // 申請內存
stu2->name = "張三";
stu2->age = 30;
stu2->score = 95.6;if (stu2 != NULL)
{free(stu2); // 釋放內存
}// cpython中的使用
typedef struct _longobject PyLongObject;

宏定義

// 用于定義常量和表達式,預編譯后會將對應的字符串替換成定義的值// 定義常量PyLong_SHIFT為30
#define PyLong_SHIFT    30// 源碼
(digit)1 << PyLong_SHIFT// 預編譯后
(digit)1 << 30

預編譯指令

#if 		// 基礎判斷
#ifdef 		// 判斷釋放有宏定義
#ifndef		// 
#else
#elif
#endif
#define		// 宏定義
#undef 		// 取消之前定義的宏
#defined// cpython
#if PYLONG_BITS_IN_DIGIT == 30
typedef uint32_t digit;
#define PyLong_SHIFT    30
#elif PYLONG_BITS_IN_DIGIT == 15
typedef unsigned short digit; 
#define PyLong_SHIFT    15
#else
#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"
#endif

assert斷言

// 用于在調試期間捕獲程序錯誤的機制
#include <assert.h>  
int x = 5;  
assert(x != 0); // 斷言 x 不等于 0

goto 語法

// 用于無條件跳轉到程序中的指定標簽int i = 0;  
for (i = 0; i < 10; i++) {  if (i == 5) {  goto end_loop; // 當 i 等于 5 時,跳轉到 end_loop 標簽處  }  printf("%d\n", i);  
}  
end_loop: // 這是 end_loop 標簽  
printf("Loop ended early.\n");  

一切皆對象

整數對象

有無符號

整數分為無符號整數和有符號整數,無符號整數只表示正數和零,而有符號整數則通過特定的編碼方式(如補碼)來表示正數、負數和零,在補碼表示法中,最高位(符號位)為0表示正數,為1表示負數。其余位則用于表示數值的大小。

整數和操作系統

  1. 位數:
  • 在32位操作系統中,整數通常使用32位來表示,即4個字節(32個比特)。
  • 在64位操作系統中,整數通常使用64位來表示,即8個字節(64個比特)。
  1. 范圍:
  • 在32位操作系統中,有符號整數的范圍通常是從 -2^31 到 2^31-1,即從 -2147483648 到 2147483647;無符號整數的范圍通常是從 0 到 2^32-1,即從 0 到 4294967295。
  • 在64位操作系統中,有符號整數的范圍通常是從 -2^63 到 2^63-1,即從 -9223372036854775808 到 9223372036854775807;無符號整數的范圍通常是從 0 到 2^64-1,即從 0 到 18446744073709551615。

整數結構體


// Include/object.h // 基礎對象,定長的
typedef struct _object {_PyObject_HEAD_EXTRA/*引用計數,用于垃圾回收*/Py_ssize_t ob_refcnt;           /*指向對象類型的指針,用于標識對象的類型,運行時類型檢查和類型特定的操作,每個對象有一個類型對象,定義了該對象的屬性、行為、方法等。PyObject 對象到底是什么類型的,只有再調用的時候,通過ob_type來判斷,即多態機制*/struct _typeobject *ob_type;    
} PyObject;// 可變長對象
typedef struct {PyObject ob_base;Py_ssize_t ob_size; /*  可變部分的項目數 */
} PyVarObject; // 定義所有可變大小容器對象的初始段。
#define PyObject_VAR_HEAD      PyVarObject ob_base;// Include/longintrepr.h
typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */struct _longobject {PyObject_VAR_HEAD// 定義了一個數組 ob_digit,其類型為 digit(即uint32_t),該數組只有一個元素digit ob_digit[1];
};// 結合上面的結構體
typedef struct {_PyObject_HEAD_EXTRAPy_ssize_t ob_refcnt; // 引用計數 8字節struct _typeobject *ob_type; // 類型 8字節Py_ssize_t ob_size; // 元素個數	8字節digit ob_digit[1]; // digit類型的數組,默認長度為1
} PyLongObject;

PyLongObject 對象中數組ob_digit 是 digit 類型的,默認長度是 1,python 中的整數就是存在這個數組中的,看下 digit 的類型


// Include/longintrepr.h
// 值為30表示64位系統,值為15表示32位系統
#if PYLONG_BITS_IN_DIGIT == 30
// uint32_t 是一個無符號32位整數類型
typedef uint32_t digit;
#define PyLong_SHIFT    30
......#elif PYLONG_BITS_IN_DIGIT == 15
// unsigned short 一個16位的無符號整數類型
typedef unsigned short digit; 
#define PyLong_SHIFT    15

當操作系統 64 位時,digit 的類型是無符號的 32 位整數類型,并且ob_digit 數組中每一位存儲的最大數字為 (2^30)-1 即1073741823,此處 30 是 PyLong_SHIFT 的值。如果一個數值大于1073741823,則數組長度通過PyLong_SHIFT 進行計算。
操作系統是 32 位,digit 的類型是一個16位的無符號整數類型,PyLong_SHIFT 值為 15。
看下longintrepr.h 中一段注釋

/* Long integer representation.The absolute value of a number is equal toSUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)Negative numbers are represented with ob_size < 0;zero is represented by ob_size == 0.In a normalized number, ob_digit[abs(ob_size)-1] (the most significantdigit) is never zero.  Also, in all cases, for all valid i,0 <= ob_digit[i] <= MASK.The allocation function takes care of allocating extra memoryso that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available.CAUTION:  Generic code manipulating subtypes of PyVarObject has toaware that ints abuse  ob_size's sign bit.
*/

PyLongObject 對象中 ob_size 即表示數組ob_digit 的長度,又表示整數的符號。
ob_size如果小于零,則表示一個負數,ob_size 如果等于零,表示 0。而整個整數的值則通過表達式來計算:
**SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)**
比如數字:1234567890987654321 在ob_digit 中的存儲:
此時 ob_size => 3; ob_digit => {829168817, 76039122, 1}
根據公式反推一下ob_digit 數組的值:
第一步:

temp = 1234567890987654321
ob_digit[0] = 829168817 => temp % (2^30)
temp = 1149780946 =>  temp // (2^30)
ob_size++

第二步:

temp = 1149780946
ob_digit[1] = 76039122 => temp % (2^30)
temp = 1 =>  temp // (2^30)
ob_size++

第三步:

temp = 1
ob_digit[2] = 1 => temp % (2^30)
temp = 0 =>  temp // (2^30)
ob_size++

根據公式反算一下 829168817*2**(30*0) + 76039122*2**(30*1) + 1*2**(30*2)
用 python 來模擬查看下PyLongObject 對象

# cpython長整數底層存儲算法
import math
import ctypesclass PyLong:SHIFT = 30MASK = (2 ** SHIFT)def parse_ob_size(self, longint):"""解析數組長度:param longint::return:"""ob_size = int(math.log(10) / math.log(self.MASK) * len(str(longint)) + 1)print(ob_size)return ob_sizedef parse_ob_digit(self, longint):n = abs(longint)ob_digit = []while n != 0:digit = n % self.MASKob_digit.append(digit)n //= self.MASKprint(ob_digit) # [829168817, 76039122, 1]def parse_ob_digit_by_struct(self, longint):"""通過訪問底層地址查看ob_digit數組:param longint::return:"""_ob_size = self.parse_ob_size(longint)class _PyLongObject(ctypes.Structure):# c_ssize_t 是一個表示 C 語言中 ssize_t 類型的外包裝類。ssize_t 是一個有符號整數類型,即 Py_ssize_t# c_void_p 是一個表示通用指針類型的外包裝類,它對應于 C 語言中的 void* 類型。void* 是一個泛型指針# c_uint32 是一個外包裝類,用于表示無符號的 32 位整數,對應于 C 語言中的 uint32_t 類型_fields_ = [("ob_refcnt", ctypes.c_ssize_t),("ob_type", ctypes.c_void_p),("ob_size", ctypes.c_ssize_t),("ob_digit", ctypes.c_uint32 * _ob_size)]long_object = _PyLongObject.from_address(id(longint))ob_size = abs(long_object.ob_size)ob_digit = long_object.ob_digit[:ob_size]print(ob_digit, ob_size) # [829168817, 76039122, 1], 3if __name__ == '__main__':pylong = PyLong()data = 1234567890987654321pylong.parse_ob_size(data)pylong.parse_ob_digit(data)pylong.parse_ob_digit_by_struct(data)

來看下幾個特殊的數是怎么存的:
0 ob_size 如果等于零,表示 0,ob_size => 0
1 ob_size => 1; ob_digit=>{1}
-1 ob_size => -1; ob_digit=>{1}
(2 ^ 30) -1 ob_size => 1; ob_digit=>{1073741823}
-(2 ^ 30) -1 ob_size => -1; ob_digit=>{1073741823}
(2 ^ 30) ob_size => 2; ob_digit=>{0, 1}
-(2 ^ 30) ob_size => -2; ob_digit=>{0, 1}
整數占內存大小
ob_refcnt 是 8 字節,ob_type 指針類型占 8 字節,ob_size 占 8 字節,ob_digit 是 4 字節。所以整數的大小是,83+ob_size 絕對值*4

import sys# 1的ob_size是1,占內存大小為24+4*1=28
sys.getsizeof(1) # 28# 0的ob_size是0,說明ob_digit長度是0,24+4*0=24sys.getsizeof(1) # 24#(2**30)-1的ob_size是1,內存大小為24+4*1=28
sys.getsizeof((2**30)-1) # 28#2**30的ob_size是2,內存大小為24+4*2=32
sys.getsizeof(2**30) # 32

創建整數的方法
PyLong_FromLong 使用 C 的 long 類型創建 python 整數
PyLong_FromUnsignedLong 使用 C 的無符號 long 類型創建
PyLong_FromDouble 使用 C 的 longlong 類型創建
PyLong_FromVoidPtr 使用 C 的 指針 類型創建
PyLong_FromLongLong 使用 C 的 longlong 類型創建
PyLong_FromUnsignedLongLong 使用 C 的無符號 longlong 類型創建
PyLong_FromSsize_t 使用 C 的Py_ssize_t 類型創建
PyLong_FromSize_t 使用 C 的size_t 類型創建
創建整數對象
_PyLong_New

PyLongObject *
_PyLong_New(Py_ssize_t size)
{PyLongObject *result; // result 是一個PyLongObject類型的指針/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +sizeof(digit)*size.  Previous incarnations of this code usedsizeof(PyVarObject) instead of the offsetof, but this risks beingincorrect in the presence of padding between the PyVarObject headerand the digits. 所需字節數為offsetof(PyLongObject, ob_digit) + sizeof(digit)*size此代碼的先前版本使用sizeof(PyVarObject)而不是offsetof,但在PyVarObject頭文件和數字之間存在填充時,這有可能是不正確的。*/if (size > (Py_ssize_t)MAX_LONG_DIGITS) {PyErr_SetString(PyExc_OverflowError,"too many digits in integer");return NULL;}/* PyObject_MALLOC 通常用于分配小塊內存offsetof(PyLongObject, ob_digit) 表示獲取 PyLongObject 結構體中 ob_digit 成員相對于結構體起始地址的偏移量申請內存存儲PyLongObject結構體和長度為size 數組 ob_digit*/result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) +size*sizeof(digit));if (!result) {PyErr_NoMemory();return NULL;}// 初始化ob_type、ob_size、ob_refcnt等值return (PyLongObject*)PyObject_INIT_VAR(result, &PyLong_Type, size);
}

整數類型

// 整數對象的類型
PyTypeObject PyLong_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"int",                                      /* tp_name */offsetof(PyLongObject, ob_digit),           /* tp_basicsize */sizeof(digit),                              /* tp_itemsize */long_dealloc,                               /* tp_dealloc 析構操作,計數器為0時,清除對象*/0,                                          /* tp_print */0,                                          /* tp_getattr */0,                                          /* tp_setattr */0,                                          /* tp_reserved */long_to_decimal_string,                     /* tp_repr */&long_as_number,                            /* tp_as_number 數值相關的操作*/0,                                          /* tp_as_sequence */0,                                          /* tp_as_mapping */(hashfunc)long_hash,                        /* tp_hash 哈希函數,是可哈希的*/0,                                          /* tp_call */long_to_decimal_string,                     /* tp_str */PyObject_GenericGetAttr,                    /* tp_getattro */0,                                          /* tp_setattro */0,                                          /* tp_as_buffer */Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |Py_TPFLAGS_LONG_SUBCLASS,               /* tp_flags */long_doc,                                   /* tp_doc */0,                                          /* tp_traverse */0,                                          /* tp_clear */long_richcompare,                           /* tp_richcompare 比較操作*/0,                                          /* tp_weaklistoffset */0,                                          /* tp_iter */0,                                          /* tp_iternext */long_methods,                               /* tp_methods 相關的函數*/0,                                          /* tp_members */long_getset,                                /* tp_getset */0,                                          /* tp_base */0,                                          /* tp_dict */0,                                          /* tp_descr_get */0,                                          /* tp_descr_set */0,                                          /* tp_dictoffset */0,                                          /* tp_init */0,                                          /* tp_alloc */long_new,                                   /* tp_new */PyObject_Del,                               /* tp_free */
};

比較操作

/* 復雜的比較操作
self    本身
other   比較對象
op      比較操作
*/
static PyObject *
long_richcompare(PyObject *self, PyObject *other, int op)
{int result;CHECK_BINOP(self, other); // 檢測 self other 是不是長整數// 兩個對象地址相同時,則表明是同一個對象,不需要比較if (self == other)result = 0;elseresult = long_compare((PyLongObject*)self, (PyLongObject*)other);Py_RETURN_RICHCOMPARE(result, 0, op);
}// 長整數比較
static int
long_compare(PyLongObject *a, PyLongObject *b)
{Py_ssize_t sign;/*對于長整數對象,Py_SIZE 返回的是數字中絕對值的位數(二進制位)。注意,這個大小是包括符號位的,所以一個正數和它的負數值會有相同的大小。對于列表、元組或其他序列類型的對象,Py_SIZE 通常返回序列中元素的數量。*/ if (Py_SIZE(a) != Py_SIZE(b)) {// a和b的ob_size不相等時,兩個ob_size相減,然后根據符號判斷哪個數大sign = Py_SIZE(a) - Py_SIZE(b);}else {// 如果a和b的ob_size相同,需要逐個比較ob_digit中的值Py_ssize_t i = Py_ABS(Py_SIZE(a));// 從后往前(因為高位的數放在后面),循環比較ob_digit中的值while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]);// a和b數組ob_digit值都一樣,執行--i后i就小于零if (i < 0)sign = 0;else {// 如果a、b的ob_digit中有1位不相同,則只需要比較當前位上的數字,就能分出大小sign = (sdigit)a->ob_digit[i] - (sdigit)b->ob_digit[i];// 如果a是負數,則比較結果就要加上負號if (Py_SIZE(a) < 0)sign = -sign;}}// 最終檢查sign的值// sign < 0, a < b// sign > 0, a > b// sign = 0, a = breturn sign < 0 ? -1 : sign > 0 ? 1 : 0;
}

整數類型的函數集

static PyNumberMethods long_as_number = {(binaryfunc)long_add,       /*nb_add 加法*/	(binaryfunc)long_sub,       /*nb_subtract 減法*/(binaryfunc)long_mul,       /*nb_multiply 乘法*/long_mod,                   /*nb_remainder 除法*/long_divmod,                /*nb_divmod 取余*/long_pow,                   /*nb_power 乘方*/(unaryfunc)long_neg,        /*nb_negative*/(unaryfunc)long_long,       /*tp_positive*/(unaryfunc)long_abs,        /*tp_absolute*/(inquiry)long_bool,         /*tp_bool*/(unaryfunc)long_invert,     /*nb_invert*/long_lshift,                /*nb_lshift*/(binaryfunc)long_rshift,    /*nb_rshift*/long_and,                   /*nb_and*/long_xor,                   /*nb_xor*/long_or,                    /*nb_or*/long_long,                  /*nb_int*/0,                          /*nb_reserved*/long_float,                 /*nb_float*/0,                          /* nb_inplace_add */0,                          /* nb_inplace_subtract */0,                          /* nb_inplace_multiply */0,                          /* nb_inplace_remainder */0,                          /* nb_inplace_power */0,                          /* nb_inplace_lshift */0,                          /* nb_inplace_rshift */0,                          /* nb_inplace_and */0,                          /* nb_inplace_xor */0,                          /* nb_inplace_or */long_div,                   /* nb_floor_divide */long_true_divide,           /* nb_true_divide */0,                          /* nb_inplace_floor_divide */0,                          /* nb_inplace_true_divide */long_long,                  /* nb_index */
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/15133.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15133.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/15133.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot線程池的 使用

一.異步方法 1.啟動類加EnableAsync注解 2.在需要異步執行的方法上添加Async注解 3.直接調用 結論&#xff1a;異步方法是通過SpringBoot中自動注入的線程池任務執行器實現的 二.自定義線程池 1.創建線程的配置類 2.使用Async注解時指定名稱 3.結論 手動注入多個線程池任務執…

Java 18新特性

Java 18引入了一系列新的特性和改進&#xff0c;這些更新覆蓋了從基本語言構造到更高級別的API等多個方面。以下是一些Java 18的主要新特性&#xff1a; 模式匹配增強&#xff1a;Java 18改進了模式匹配功能&#xff0c;使其更加強大和易于使用。開發人員可以使用模式匹配來簡…

Linux echo命令(在終端輸出文本)

文章目錄 Linux Echo命令深度解析簡介命令語法常見選項- -n&#xff1a;不輸出行尾的換行符&#xff0c;這意味著輸出后不會換到下一行。- -e&#xff1a;啟用反斜杠轉義的解釋&#xff0c;允許使用特殊字符。- -E&#xff1a;禁用反斜杠轉義的解釋&#xff08;默認選項&#x…

基于地理坐標的高階幾何編輯工具算法(2)——相交面裁剪

文章目錄 工具步驟應用場景算法輸入算法輸出算法示意圖算法原理后處理 工具步驟 選中一個需要裁剪的面&#xff0c;點擊“相交面裁剪”工具&#xff0c;多選裁剪模板面&#xff0c;空格執行。 應用場景 常用于基于遙感影像的建筑物幾何面編輯。 算法輸入 一個待裁剪的面&a…

sqlserver的查詢(三)

目錄 10. group by(分組) 11. having(對分組后的信息過濾) 可能從這里開始&#xff0c;執行順序越來越顯得重要了&#xff01;&#xff01;&#xff01; 10. group by(分組) 這個查詢相比前面會有一些困難&#xff1b; 格式&#xff1a;group by 字段的集合&#xff1b; 功…

Java進階學習筆記8——單繼承、Object類、方法重寫

Java 是單繼承的&#xff0c;Java中的類不支持多繼承&#xff0c;但是支持多層繼承。 Object類是所有類的父類。 Java不支持多類繼承&#xff1a; Java支持多層繼承&#xff1a; 反證法&#xff1a; Object類&#xff1a; Object類是java所有類的祖宗類&#xff0c;我們寫的任…

AI爆文寫作:我一般不告訴別人的爆文玩法:如何100%抄襲10W+的爆文標題,讓你也篇篇爆款

有現成的10w擺在眼前我們要做的就是&#xff0c;100%抄標題&#xff0c;以及內容重述。 具體操作步驟&#xff1a; 找到適合自己賬號選題的10w(微信看一看或者頭條)100%抄爆文的標題將這篇文章喂給Al&#xff0c;讓AI分析文章的寫法和主題根據提煉出來的寫法和主題&#xff0…

使用魚香肉絲一鍵安裝重新安裝ROS后mavros節點報錯,.so文件不匹配

解決方案&#xff1a; 1、寫在mavros相關軟件&#xff0c;共卸載7個包 sudo apt-get remove ros-melodic-mav*2、重新安裝mavros&#xff0c;共安裝10個包 sudo apt-get remove ros-melodic-mav*

每日AIGC最新進展(10):符號音樂生成SYMPLEX、新型圖像編輯數據集ReasonPix2Pix、角色一致性插畫生成、高級的風格個性化擴散模型

Diffusion Models專欄文章匯總&#xff1a;入門與實戰 SYMPLEX: Controllable Symbolic Music Generation using Simplex Diffusion with Vocabulary Priors http://arxiv.org/abs/2405.12666v1 本文介紹了一種新的符號音樂生成方法&#xff0c;名為SYMPLEX&#xff0c;它基于…

pod 庫發布腳本

repo_tag.sh 文件 #!/bin/zsh# 私有庫名稱 #PODNAME${PWD##*/} PODNAME"LBHorizontalCenterLayout"function obtain_git_tag {# 類似 "s.version 0.0.1"VERSION_STRINGgrep -E s.version.* ${PODNAME}.podspecTAGtr -cd "[0-9.]" <<&…

使用 JavaParser 解析代碼

[自用] 如何判斷出 java 代碼文本中一個方法的輸入參數個數以及類型。用結構體數組存儲遍歷信息&#xff0c;最后用一個方法實現打印。可以使用第三方庫。 如果是一個語句如何判斷這個語句中的局部變量個數和類型。那么該怎么實現呢&#xff1f; 要判斷 Java 代碼文本中一個方…

【電源專題】什么是層間短路(Rare Short),如何檢測?

層間短路發生的原因 一般線圈類制品是以漆包線纏繞導磁材料制造而成,漆包線是指外層披覆一層薄薄絕緣漆的銅線。我們常見的線圈類制品有: 電源變壓器、 高壓變壓器、 Switching Power 變壓器、 通訊變壓器、 脈沖變壓器、 環型變壓器、 電力傳輸變壓器、 音頻傳輸變壓器、 電…

k8s pvc pending waiting for first consumer to be created before binding

動態創建PV失敗且提示waiting for first consumer to be created before binding 問題現象 使用WaitForFirstConsumer的StorageClass創建PV失敗&#xff0c;PVC Event提示persistentvolume-controller waiting for first consumer to be created before binding。 問題原因 PV…

c# mysql 加鎖解鎖

c# mysql 加鎖解鎖 在C#中操作MySQL實現加鎖和解鎖&#xff0c;通常是通過執行特定的SQL語句來完成。MySQL支持表級鎖定和行級鎖定。以下是使用MySQL命令執行加鎖和解鎖的示例代碼&#xff1a; using MySql.Data.MySqlClient;// 連接字符串 string connStr "serverloca…

【QGIS入門實戰精品教程】5.3:CGCS2000轉Lambert投影

參考閱讀: 【GlobalMapper精品教程】081:WGS84/CGCS2000轉Lambert投影 文章目錄 一、加載實驗數據二、投影轉換三、批量投影轉換一、加載實驗數據 加載配套實驗數據,如下圖所示:圖層為長沙市范圍、長沙市酒店賓館分布點位、湖南省酒店分布點位矢量數據。 雙擊圖層,打開信…

網段與廣播域

ip地址與子網掩碼做與運算得到網絡號&#xff0c;得到的網絡號相同就是同一個網段&#xff0c;否則不是&#xff0c;跟他們在什么位置沒有任何關系 這里面pc3和前兩個pc雖然不在同一個網段&#xff0c;但是pc1發廣播包的時候&#xff0c;pc3也能收到&#xff0c;因為路由器的所…

Vue 安裝vue

1、官網安裝下載安裝nodejs 2、安裝完成后&#xff0c;通過命令查看版本,可以查看到版本 node -v npm -v 3、安裝Vue CLi npm install -g vue/cli 4、創建項目,vue create test 如果遇到報錯&#xff1a; ERROR Error: spawn yarn ENOENT Error: spawn yarn ENOENT at ChildP…

前端基礎入門三大核心之HTML篇:深入理解重繪與重排 —— 概念、區別與實戰演練

前端基礎入門三大核心之HTML篇&#xff1a;深入理解重繪與重排 —— 概念、區別與實戰演練 HTML渲染基礎回顧重繪與重排的概念重繪&#xff08;Repaint&#xff09;重排&#xff08;Reflow&#xff09; 區別與影響實戰示例&#xff1a;優化策略與代碼演示示例1&#xff1a;避免…

Dilworth 定理

這是一個關于偏序集的定理&#xff0c;事實上它也可以擴展到圖論&#xff0c;dp等中&#xff0c;是一個很有意思的東西 偏序集 偏序集是由集合 S S S以及其上的一個偏序關系 R R R定義的&#xff0c;記為 ( S , R ) (S,R) (S,R) 偏序關系&#xff1a; 對于一個二元關系 R ?…

用 vue3 + phaser 實現經典小游戲:飛機大戰

本文字數&#xff1a;7539字 預計閱讀時間&#xff1a;30分鐘 01 前言 說起小游戲&#xff0c;最經典的莫過于飛機大戰了&#xff0c;相信很多同學都玩過。今天我們也來試試開發個有趣的小游戲吧&#xff01;我們將從零開始&#xff0c;看看怎樣一步步實現一個H5版的飛機大戰&a…