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.mzph.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…