CPython源码学习5:字节对象

字节的结构体 PyBytesObject

浮点数的结构体 PyBytesObject ,定义在头文件 Include/bytesobject.h 中,包含PyObject_VAR_HEAD 说明字节是可变大小的对象。

// Include/bytesobject.h
typedef struct {PyObject_VAR_HEAD // 可变大小的对象Py_hash_t ob_shash;char ob_sval[1];/* Invariants:*     ob_sval contains space for 'ob_size+1' elements.*     ob_sval[ob_size] == 0.*     ob_shash is the hash of the string or -1 if not computed yet.*/
} PyBytesObject;// 展开 PyObject_VAR_HEAD
typedef struct {_PyObject_HEAD_EXTRAPy_ssize_t ob_refcnt; 			// 引用计数 8字节struct _typeobject *ob_type; 	// 类型 8字节Py_ssize_t ob_size;				// 对象包含的元素数量,即字节序列的长度Py_hash_t ob_shash;				// 哈希值,如果哈希值尚未计算,通常会将其设置为 -1char ob_sval[1];				// 字节序列的实际数据,其长度为 1,但实际分配的内存可能大于 1,C语言中字节序列以 \0 字符结尾,计算ob_size的时候不包括\0	
}

字节内存大小

把 PyBytesObject 展开后发现ob_refcnt 是整数型长度 8 字节,ob_type 是指针长度是 8 字节,ob_size 是整数型长度是 8 字节,ob_shash 是整数型长度是 8 字节,ob_sval 是 char 类型的数组长度是 n 1 字节 再加上末尾的 \0 的 1 字节,所以字节对象的大小是变长的 32+n1+1 字节,可以在 Python 中验证。

s = b"" # 空字节串长度为0 内存占用为  32 + 0*1 + 1 = 33
s.__sizeof__() # 33s1 = b'0x1715f7b01e0' # 字节长度为 13,内存占用 32 + 13 * 1 + 1 = 46
s1.__sizeof__() # 46# 另一种计算方式
import sys
sys.getsizeof(s1) # 46

字节的类型对象 PyBytes_Type

字节对象的类型的结构体是 PyBytes_Type,定义在头文件 Include/bytesobject.c 中。和其他类型对象一样,提供了多个函数来检查和操作字节对象,包括字节的创建bytes_new、字节的销毁bytes_dealloc、字节的函数集bytes_as_number 包含取余等计算、序列对象的方法集bytes_as_sequence、映射相关的方法集bytes_as_mapping、字节的哈希计算bytes_hash、用于生成字节字符串表示的函数bytes_repr 等等。

// Objects/bytesobject.c
PyTypeObject PyBytes_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"bytes",PyBytesObject_SIZE,				// tp_basicsize 基本大小 sizeof(char),					// tp_itemsize可变长对象的每个元素的大小bytes_dealloc,                      /* tp_dealloc */0,                                          /* tp_print */0,                                          /* tp_getattr */0,                                          /* tp_setattr */0,                                          /* tp_reserved */(reprfunc)bytes_repr,                       /* tp_repr */&bytes_as_number,                           /* tp_as_number */&bytes_as_sequence,                         /* tp_as_sequence */&bytes_as_mapping,                          /* tp_as_mapping */(hashfunc)bytes_hash,                       /* tp_hash */0,                                          /* tp_call */bytes_str,                                  /* tp_str */PyObject_GenericGetAttr,                    /* tp_getattro */0,                                          /* tp_setattro */&bytes_as_buffer,                           /* tp_as_buffer */Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |Py_TPFLAGS_BYTES_SUBCLASS,              /* tp_flags */bytes_doc,                                  /* tp_doc */0,                                          /* tp_traverse */0,                                          /* tp_clear */(richcmpfunc)bytes_richcompare,             /* tp_richcompare */0,                                          /* tp_weaklistoffset */bytes_iter,                                 /* tp_iter */0,                                          /* tp_iternext */bytes_methods,                              /* tp_methods */0,                                          /* tp_members */0,                                          /* tp_getset */&PyBaseObject_Type,                         /* tp_base */0,                                          /* tp_dict */0,                                          /* tp_descr_get */0,                                          /* tp_descr_set */0,                                          /* tp_dictoffset */0,                                          /* tp_init */0,                                          /* tp_alloc */bytes_new,                                  /* tp_new */PyObject_Del,                               /* tp_free */
};

但是和浮点数类型不一样的地方,tp_basicsize 对应的是PyBytesObject_SIZE,tp_itemsize 对应的是sizeof(char)

// Objects/bytesobject.c
// 用于计算 PyBytesObject 结构体的基本大小,不包括存储在 ob_sval 字段中的实际字节数据
#define PyBytesObject_SIZE (offsetof(PyBytesObject, ob_sval) + 1)// ob_sval的类型是char的数组,所以数组中每个元素的长度为sizeof(char)
sizeof(char)

值为 0 的字段表示这些字段在初始化时没有被显式赋值或使用了默认值,即最终调用的时候使用的是 PyTypeObject 中对应的值。

  • tp_print: 设为 0 表示没有定义打印函数,继承了PyTypeObject 中的打印函数。
  • tp_getattrtp_setattr: 设为 0 表示没有定义获取和设置属性的函数。
  • tp_call: 设为 0 表示这个类型对象不能被调用(即 float 对象不是可调用的)。
  • tp_init: 设为 0 表示继承了PyTypeObject 中的初始化函数。

字节创建

第一种和浮点数一样是通过类型对象创建,调用类型对象中的 tp_new 函数,字节对象对应的是 bytes_new,可以看到经过一些列的检测和判断,最终落在了 PyBytes_FromObject 函数上。
看下类型对象创建时 python 中的函数 bytes 调用和传参

"""
help(bytes)class bytes(object)|  bytes(iterable_of_ints) -> bytes|  bytes(string, encoding[, errors]) -> bytes|  bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer|  bytes(int) -> bytes object of size given by the parameter initialized with null bytes|  bytes() -> empty bytes object|  |  Construct an immutable array of bytes from:|    - an iterable yielding integers in range(256)|    - a text string encoded using the specified encoding|    - any object implementing the buffer API.|    - an integer"""
bytes([1,2,3,4]) 				# b'\x01\x02\x03\x04'
bytes("1234", encoding="gbk") 	# b'1234'
bytes(b"1234") 					# b'1234'
bytes(4) 						# b'\x00\x00\x00\x00' 生成长度为4的 null 字节
bytes()							# b''

python 中b = bytes(b"1234")通过类型对象创建字节对象。

// Objects/bytesobject.c
static PyObject *
bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{PyObject *x = NULL;const char *encoding = NULL;const char *errors = NULL;PyObject *new = NULL;PyObject *func;Py_ssize_t size;static char *kwlist[] = {"source", "encoding", "errors", 0};_Py_IDENTIFIER(__bytes__);if (type != &PyBytes_Type)return bytes_subtype_new(type, args, kwds);if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:bytes", kwlist, &x,&encoding, &errors))return NULL;if (x == NULL) { // 调用bytes()时会走到这if (encoding != NULL || errors != NULL) {PyErr_SetString(PyExc_TypeError,"encoding or errors without sequence ""argument");return NULL;}return PyBytes_FromStringAndSize(NULL, 0);}if (encoding != NULL) {// 调用 bytes("123", encoding="gbk") 会走到这/* Encode via the codec registry */if (!PyUnicode_Check(x)) {PyErr_SetString(PyExc_TypeError,"encoding without a string argument");return NULL;}new = PyUnicode_AsEncodedString(x, encoding, errors);if (new == NULL)return NULL;assert(PyBytes_Check(new));return new;}if (errors != NULL) {PyErr_SetString(PyExc_TypeError,PyUnicode_Check(x) ?"string argument without an encoding" :"errors without a string argument");return NULL;}/* We'd like to call PyObject_Bytes here, but we need to check for aninteger argument before deferring to PyBytes_FromObject, somethingPyObject_Bytes doesn't do. */func = _PyObject_LookupSpecial(x, &PyId___bytes__);if (func != NULL) {new = _PyObject_CallNoArg(func);Py_DECREF(func);if (new == NULL)return NULL;if (!PyBytes_Check(new)) {PyErr_Format(PyExc_TypeError,"__bytes__ returned non-bytes (type %.200s)",Py_TYPE(new)->tp_name);Py_DECREF(new);return NULL;}return new;}else if (PyErr_Occurred())return NULL;if (PyUnicode_Check(x)) {PyErr_SetString(PyExc_TypeError,"string argument without an encoding");return NULL;}/* Is it an integer? */if (PyIndex_Check(x)) {// 调用 bytes(3) 会走到这size = PyNumber_AsSsize_t(x, PyExc_OverflowError);if (size == -1 && PyErr_Occurred()) {if (!PyErr_ExceptionMatches(PyExc_TypeError))return NULL;PyErr_Clear();  /* fall through */}else {if (size < 0) {PyErr_SetString(PyExc_ValueError, "negative count");return NULL;}new = _PyBytes_FromSize(size, 1);if (new == NULL)return NULL;return new;}}// 调用 bytes(b"123") 会走到这return PyBytes_FromObject(x);
}// 用于将一个对象转换为字节对象
// 函数尝试通过调用对象的 __bytes__ 方法或其他合适的转换方式来生成字节对象
PyObject *
PyBytes_FromObject(PyObject *x)
{PyObject *it, *result;if (x == NULL) {PyErr_BadInternalCall();return NULL;}// 检查输入对象是否已经是字节对象if (PyBytes_CheckExact(x)) {Py_INCREF(x);return x;}/* Use the modern buffer interface */if (PyObject_CheckBuffer(x))return _PyBytes_FromBuffer(x);if (PyList_CheckExact(x))return _PyBytes_FromList(x);if (PyTuple_CheckExact(x))return _PyBytes_FromTuple(x);if (!PyUnicode_Check(x)) {it = PyObject_GetIter(x);if (it != NULL) {result = _PyBytes_FromIterator(it, x);Py_DECREF(it);return result;}if (!PyErr_ExceptionMatches(PyExc_TypeError)) {return NULL;}}PyErr_Format(PyExc_TypeError,"cannot convert '%.200s' object to bytes",x->ob_type->tp_name);return NULL;
}

第二种是通过 C API 进行创建,python 中b = b"1234"通过 C API 创建字节对象。

// Objects/bytesobject.cPyObject *
PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
{PyBytesObject *op;if (size < 0) {// 如果 len 为负数,函数会设置 PyExc_SystemError 异常并返回 NULLPyErr_SetString(PyExc_SystemError,"Negative size passed to PyBytes_FromStringAndSize");return NULL;}if (size == 1 && str != NULL &&(op = characters[*str & UCHAR_MAX]) != NULL){
#ifdef COUNT_ALLOCSone_strings++;
#endifPy_INCREF(op);return (PyObject *)op;}// 使用 PyObject_Malloc 为 PyBytesObject 分配内存。// 分配的大小是 sizeof(PyBytesObject) + len,以便存储字节对象本身和它的内容op = (PyBytesObject *)_PyBytes_FromSize(size, 0);if (op == NULL)return NULL;if (str == NULL)return (PyObject *) op;// 如果 v 非 NULL,使用 memcpy 将 v 指向的字符串的前 len 个字节复制到新分配的字节对象中memcpy(op->ob_sval, str, size);/* share short strings */if (size == 1) {characters[*str & UCHAR_MAX] = op;Py_INCREF(op);}// 将新创建并初始化的 PyBytesObject 转换为 PyObject*,并返回给调用者return (PyObject *) op;
}static PyObject *
_PyBytes_FromSize(Py_ssize_t size, int use_calloc)
{PyBytesObject *op;assert(size >= 0);if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCSnull_strings++;
#endifPy_INCREF(op);return (PyObject *)op;}if ((size_t)size > (size_t)PY_SSIZE_T_MAX - PyBytesObject_SIZE) {PyErr_SetString(PyExc_OverflowError,"byte string is too large");return NULL;}/* Inline PyObject_NewVar */if (use_calloc)op = (PyBytesObject *)PyObject_Calloc(1, PyBytesObject_SIZE + size);elseop = (PyBytesObject *)PyObject_Malloc(PyBytesObject_SIZE + size);if (op == NULL)return PyErr_NoMemory();// 使用 PyObject_Init_VAR 初始化变量长度对象 (PyVarObject)(void)PyObject_INIT_VAR(op, &PyBytes_Type, size);op->ob_shash = -1;// 无论 v 是否为 NULL,都将新字节对象的末尾设置为 '\0'if (!use_calloc)op->ob_sval[size] = '\0';/* empty byte string singleton */if (size == 0) {nullstring = op;Py_INCREF(op);}// 将新创建并初始化的 PyBytesObject 转换为 PyObject*,并返回给调用者return (PyObject *) op;
}

字节对象的销毁

销毁对象是调用指针 tp_dealloc 所指的函数,字节对象对应的就是 bytes_dealloc,可以看到直接调用了tp_free(op)函数, tp_free内存释放函数指向 PyObject_Free,负责实际的内存释放。

// Objects/bytesobject.cstatic void
bytes_dealloc(PyObject *op)
{Py_TYPE(op)->tp_free(op);
}

字节的缓存机制

字节对象的缓存是一个PyBytesObject 类型的数组,存在characters 中,长度为 256。

// Objects/bytesobject.c
#define UCHAR_MAX     0xffstatic PyBytesObject *characters[UCHAR_MAX + 1];PyObject *
PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
{PyBytesObject *op;if (size < 0) {// 如果 len 为负数,函数会设置 PyExc_SystemError 异常并返回 NULLPyErr_SetString(PyExc_SystemError,"Negative size passed to PyBytes_FromStringAndSize");return NULL;}// 长度为1的字节,如果在缓存中,就直接获取并返回if (size == 1 && str != NULL &&(op = characters[*str & UCHAR_MAX]) != NULL){
#ifdef COUNT_ALLOCSone_strings++;
#endifPy_INCREF(op);return (PyObject *)op;}// 使用 PyObject_Malloc 为 PyBytesObject 分配内存。// 分配的大小是 sizeof(PyBytesObject) + len,以便存储字节对象本身和它的内容op = (PyBytesObject *)_PyBytes_FromSize(size, 0);if (op == NULL)return NULL;if (str == NULL)return (PyObject *) op;// 如果 v 非 NULL,使用 memcpy 将 v 指向的字符串的前 len 个字节复制到新分配的字节对象中memcpy(op->ob_sval, str, size);/* share short strings */// 长度为1时,缓存起来if (size == 1) {characters[*str & UCHAR_MAX] = op;Py_INCREF(op);}// 将新创建并初始化的 PyBytesObject 转换为 PyObject*,并返回给调用者return (PyObject *) op;
}

缓存过程:
1、当字节长度为 1,并且不为空的时候,会缓存在characters 中
2、当初始化的时候,长度为 1 的字节,先会判断是否在缓存中,如果在缓存中就直接返回。
在 python 中验证 :

"""
两个单字节的地址一样,多字节的地址不同
"""
a = b'a'
id(a) # 2581807388640z = b'a'
id(z) # 2581807388640a1 = b"abc"
id(a1) # 1902678903424
z1 = b"abc"
id(z1) # 1902678904480

字节的属性和函数

PyBytes_Type 中还定义了一些字节对象相关的属性和函数等
bytes_hash 字节的哈希值
可以看到计算完哈希后,将哈希值也赋给了字节对象的ob_shash,因为字节对象的哈希是经常用到的,所以为了效率计算一次后,保存在对象中。

static Py_hash_t
bytes_hash(PyBytesObject *a)
{if (a->ob_shash == -1) {/* Can't fail */a->ob_shash = _Py_HashBytes(a->ob_sval, Py_SIZE(a));}return a->ob_shash;
}

bytes_as_number 结构体是所有数值的函数集,但是只包含取余函数,但是真实的函数功能并不是取余,而是用来%格式化字节串。

static PyNumberMethods bytes_as_number = {0,              /*nb_add*/0,              /*nb_subtract*/0,              /*nb_multiply*/bytes_mod,      /*nb_remainder*/};static PyObject *
bytes_mod(PyObject *self, PyObject *arg)
{if (!PyBytes_Check(self)) {Py_RETURN_NOTIMPLEMENTED;}// 格式化字节串return _PyBytes_FormatEx(PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self),arg, 0);
}

bytes_as_sequence 结构体是所有序列的函数集,包含长度、连接、重复、是否包含、索引等

static PySequenceMethods bytes_as_sequence = {(lenfunc)bytes_length, /*sq_length 查看序列的长度 */(binaryfunc)bytes_concat, /*sq_concat 合并两个字节串 */(ssizeargfunc)bytes_repeat, /*sq_repeat 使用*重复多次字节 */(ssizeargfunc)bytes_item, /*sq_item 索引单个字节返回整形,切片返回字节*/0,                  /*sq_slice*/0,                  /*sq_ass_item*/0,                  /*sq_ass_slice*/(objobjproc)bytes_contains /*sq_contains 是否包含 in */
};

bytes_length 获取对象长度

static Py_ssize_t
bytes_length(PyBytesObject *a)
{return Py_SIZE(a);
}

bytes_concat 拼接两个字节串

static PyObject *
bytes_concat(PyObject *a, PyObject *b)
{Py_buffer va, vb;PyObject *result = NULL;va.len = -1;vb.len = -1;if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 ||PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) {PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",Py_TYPE(b)->tp_name, Py_TYPE(a)->tp_name);goto done;}/* Optimize end cases */if (va.len == 0 && PyBytes_CheckExact(b)) {result = b;Py_INCREF(result);goto done;}if (vb.len == 0 && PyBytes_CheckExact(a)) {result = a;Py_INCREF(result);goto done;}if (va.len > PY_SSIZE_T_MAX - vb.len) {PyErr_NoMemory();goto done;}result = PyBytes_FromStringAndSize(NULL, va.len + vb.len);if (result != NULL) {memcpy(PyBytes_AS_STRING(result), va.buf, va.len);memcpy(PyBytes_AS_STRING(result) + va.len, vb.buf, vb.len);}done:if (va.len != -1)PyBuffer_Release(&va);if (vb.len != -1)PyBuffer_Release(&vb);return result;
}

字节相关的宏定义和函数


#define PyBytes_Check(op) \PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_BYTES_SUBCLASS)#define PyBytes_CheckExact(op) (Py_TYPE(op) == &PyBytes_Type)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/25652.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度解析地铁票务系统的技术架构与创新应用

在城市交通体系中&#xff0c;地铁作为一种快速、便捷的公共交通方式&#xff0c;已经成为现代都市生活的重要组成部分。而地铁票务系统的技术架构&#xff0c;则是支撑地铁运营的核心之一。本文将深度解析地铁票务系统的技术架构与创新应用&#xff0c;从系统设计、数据管理、…

高德地图官网文档

高德地图官网文档&#xff08;快速上手-入门-教程-地图 JS API 1.4 | 高德地图API&#xff09;

【PL理论】(16) 形式化语义:语义树 | <Φ, S> ⇒ M | 形式化语义 | 为什么需要形式化语义 | 事实:部分编程语言的设计者并不会形式化语义

&#x1f4ad; 写在前面&#xff1a;本章我们将继续探讨形式化语义&#xff0c;讲解语义树&#xff0c;然后我们将讨论“为什么需要形式化语义”&#xff0c;以及讲述一个比较有趣的事实&#xff08;大部分编程语言设计者其实并不会形式化语义的定义&#xff09;。 目录 0x00…

adb shell进入设备后的命令

目录 一、查看删除手机 /data/local/tmp/下的文件 二、设置权限 三、查看手机设备正在运行的服务 四、可能需要的adb 命令 一、查看删除手机 /data/local/tmp/下的文件 可以通过以下命令&#xff1a; adb shell # 进入设备 ls /data/local/tmp/ # 查看文件夹下的内容…

DDMA信号处理以及数据处理的流程---原始数据生成

Hello&#xff0c;大家好&#xff0c;我是Xiaojie&#xff0c;好久不见&#xff0c;欢迎大家能够和Xiaojie一起学习毫米波雷达知识&#xff0c;Xiaojie准备连载一个系列的文章—DDMA信号处理以及数据处理的流程&#xff0c;本系列文章将从目标生成、信号仿真、测距、测速、cfar…

服务部署:Linux系统部署C# .NET项目

1. 安装 .NET SDK 首先&#xff0c;你需要在你的 Linux 系统上安装 .NET SDK。 Ubuntu系统&#xff1a; 下载 Microsoft 包配置文件 wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb 这个命令使用 wge…

大模型日报2024-06-10

大模型日报 2024-06-10 大模型资讯 无需矩阵乘法的语言模型在亿参数规模上表现优异 摘要: 研究表明&#xff0c;无需矩阵乘法的语言模型在亿参数规模上仍能保持顶级性能。这一发现挑战了传统神经网络依赖矩阵乘法的观点&#xff0c;展示了在GPU优化之外的新可能性。 博弈论助力…

MySQL基础---库的操作和表的操作(配着自己的实操图,简单易上手)

绪论​ 勿问成功的秘诀为何&#xff0c;且尽全力做您应该做的事吧。–美华纳&#xff1b;本章是MySQL的第二章&#xff0c;本章主要写道MySQL中库和表的增删查改以及对库和表的备份处理&#xff0c;本章是基于上一章所写若没安装mysql可以查看Linux下搭建mysql软件及登录和基本…

编曲市场行情

编曲市场行情 现在的编曲市场是分层级&#xff0c;金字塔模式的市场&#xff0c;对能力要求很高&#xff0c;也非常卷&#xff0c;也确实能赚钱。 底层编曲人&#xff1a;数量最多&#xff0c;以初学者编曲人居多&#xff0c;大部分是那种自学了一个多月就出来标榜自己 是音…

LabVIEW汽车电机测试系统

1. 背景 随着电动汽车的快速发展&#xff0c;汽车电机作为电动汽车的核心部件&#xff0c;其性能评估变得尤为重要。电机的功率、效率、转速等参数直接影响着电动汽车的性能和续航里程。因此&#xff0c;设计一套全面、准确的汽车电机测试系统对于提高电动汽车的性能和安全性具…

离散数学-万字课堂笔记-期末考试-考研复习-北航离散数学1

第一章 逻辑语言1.1 逻辑运算1.2 命题逻辑合式公式1.3 谓词逻辑合式公式1.4 自然语言命题第二章 命题逻辑语义2.1 命题合式公式语义2.2 推论式与等价式的语义2.3 变换合式公式的语义2.4 命题公式范式2.5 等式演算2.6 完全集第三章 谓词逻辑语义3.1谓词合式公式语义3.2推论关系和…

从渲染管线到着色器Shader实践

浏览器渲染管线原理 浏览器渲染管线是浏览器将HTML、CSS和JavaScript转换为用户可见的网页的过程。这一过程涉及多个步骤,包括解析、布局、绘制和合成等。下面是浏览器渲染管线的详细原理: 解析(Parsing): HTML解析:浏览器下载HTML内容后,首先进行HTML解析,将HTML文本…

GO语言 环境搭建

1. ide GoLand 下载地址 感谢您下载GoLand&#xff01;

如何提升自己的管理思维?

贯彻组织的核心价值观和文化理念&#xff0c;营造积极正向的工作氛围。通过身体力行&#xff0c;管理者可以影响和带动团队成员&#xff0c;共同营造一个充满活力和凝聚力的工作环境&#xff0c;确保组织文化能够深入人心&#xff0c;成为推动组织前进的强大动力。 总之&#x…

“程序员职业素养全解析:技能、态度与价值观的融合“

文章目录 每日一句正能量前言专业精神专业精神的重要性技术执着追求的故事结论 沟通能力沟通能力的重要性团队合作意识实际工作中的沟通案例结论 持续学习持续学习的重要性学习方法进步经验结论 后记 每日一句正能量 梦不是为想象&#xff0c;而是让我们继续前往。 前言 在数字…

【PowerDesigner】创建和管理CDM之新建实体

目录 &#x1f30a;1. PowerDesigner简介 &#x1f30d;1.1 常用模型文件 &#x1f30d;1.2 PowerDesigner使用环境 &#x1f30a;2. 创建和管理CDM &#x1f30d;​​​​​​2.1 新建CDM &#x1f30d;2.2 新建实体 &#x1f30a;1. PowerDesigner简介 &#x1f30d;1…

【Linux系统化学习】网络层——IP协议

目录 IP协议 协议头格式 两个问题 网段划分 IP地址的分类 CIDR网段划分&#xff08;无分类编址&#xff09; 特殊的IP地址 IP地址的数量限制 私有IP地址和公网IP地址 路由 路由表的查询 IP协议 应用层、运输层上两层协议我们只考虑的是通信的双方对应层&#xff0c;…

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(六)---- 初窥操作系统启动流程(xv6启动)

系列文章目录 操作系统入门系列-MIT6.S081&#xff08;操作系统&#xff09;学习笔记&#xff08;一&#xff09;---- 操作系统介绍与接口示例 操作系统入门系列-MIT6.828&#xff08;操作系统工程&#xff09;学习笔记&#xff08;二&#xff09;----课程实验环境搭建&#x…

k8s离线部署Calico网络(2续)

下载离线镜像 百度网盘 链接&#xff1a;https://pan.baidu.com/s/14ReJW-ZyYZFLbwSEBZK6mA?pwdi6ct 提取码&#xff1a;i6ct 1.将离线镜像上传至所有服务器并解压&#xff1a; [rootmaster ~]# tar xf calico.tar.gz [rootmaster ~]# cd calico 2.所有服务器使用for循环导入…

ARM交叉编译

目录 一、介绍 1、本地编译 2、交叉编译 二、交叉工具链 1、概念 2、工具 3、获取方法 三、交叉编译运行程序 1、pc机操作&#xff08;x86_64&#xff09; ​2、开发板操作&#xff08;ARM&#xff09; 一、介绍 1、本地编译 本地编译是在与目标运行环境相同的机器上…