Mac上php版本切换
收藏以便后用,懒就截图了。
文章转自:https://zhuanlan.zhihu.com/p/179272753
文章转自:https://zhuanlan.zhihu.com/p/179272753
# Virtual hosts
Include /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf
<VirtualHost *:80>
DocumentRoot "/Users/liziyu/website/xfcms_base/public"
ServerName xfcms-base.local
Options Indexes FollowSymLinks
<Directory />
AllowOverride All
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
</Directory>
</VirtualHost>
祝所有看到此log
的朋友,2022
行大运、发大财!
PK:primary key
主键
NN:not null
非空
UQ:unique
唯一索引
BIN:binary
二进制数据(比text
更大的二进制数据)
UN:unsigned
无符号 整数(非负数)
ZF:zero fill
填充0 例如字段内容是1 int(4)
, 则内容显示为0001
AI:auto increment
自增
G:generated column
生成列
\g、\G
的意思:\g
的作用是分号和在sql语句中写“;”是等效的\G
的作用是将查到的结构旋转90度变成纵向(换行打印)
位是计算机存储的最小单位,简记为b
,也称为比特(bit)
计算机中用二进制中的0和1来表示数据,一个0或1就代表一位。位数通常指计算机中一次能处理的数据大小;
比特(bit)
是由英文BIT
音译而来,比特同时也是二进制数字中的位,是信息量的度量单位,为信息量的最小单位;
字节,英文Byte
,是计算机用于计量存储容量的一种计量单位,通常情况下一字节等于八位,字节同时也在一些计算机编程语言中表示数据类型和语言字符,在现代计算机中,一个字节等于八位;
字是表示计算机自然数据单位的术语,在某个特定计算机中,字是其用来一次性处理事务的一个固定长度的位(bit)
组,在现代计算机中,一个字等于两个字节。
什么是大端?什么是小端?
主要针对的是CPU向内存写入数据的两种方式:
大端序:将高位字节保存在内存的低地址(高位字节在前)的方式。
小端序:将高位字节保存在内在存的高地址(低位字节在前)的方式。
假设在 0x20
号开始的地址中保存4字节 int
型数据 0x12345678
,大端序CPU
保存方式如下图所示:
上图1:整数 0x12345678
的大端序字节表示。
比如说1在高位就是高位字节,相反8就在低位是低位字节
对于大端序,最高位字节 0x12
存放到低位地址,最低位字节 0x78
存放到高位地址。小端序的保存方式如下图所示:
上图2:整数 0x12345678
的小端序字节表示。
比如说1在高位就是高位字节,相反8就在低位是低位字节
不同CPU
保存和解析数据的方式不同(主流的Intel
系列CPU
为小端序),小端序系统和大端序系统通信时会发生数据解析错误。因此在发送数据前,要将数据转换为统一的格式——网络字节序(Network Byte Order
)。网络字节序统一为大端序。主机A先把数据转换成大端序再进行网络传输,主机B收到数据后先转换为自己的格式再解析。网络字节序转换函数
在 sockaddr_in
结构体,其中就用到了网络字节序转换函数,如下所示:
//创建sockaddr_in结构体变量
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1234); //端口号
htons()
用来将当前主机字节序转换为网络字节序,其中h
代表主机(host
)字节序,n
代表网络(network
)字节序,s
代表short
,htons
是 h、to、n、s
的组合,可以理解为”将short
型数据从当前主机字节序转换为网络字节序“。常见的网络字节转换函数有:htons()
:host to network short
,将short
类型数据从主机字节序转换为网络字节序。ntohs():network to host short
,将short
类型数据从网络字节序转换为主机字节序。htonl():host to network long
,将long
类型数据从主机字节序转换为网络字节序。ntohl():network to host long
,将long
类型数据从网络字节序转换为主机字节序。
通常,以s
为后缀的函数中,s
代表2个字节short
,因此用于端口号转换;以l
为后缀的函数中,l
代表4个字节的long
,因此用于IP
地址转换。举例说明上述函数的调用过程:
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
int main(){
unsigned short host_port = 0x1234, net_port;
unsigned long host_addr = 0x12345678, net_addr;
net_port = htons(host_port);
net_addr = htonl(host_addr);
printf("Host ordered port: %#x\n", host_port);
printf("Network ordered port: %#x\n", net_port);
printf("Host ordered address: %#lx\n", host_addr);
printf("Network ordered address: %#lx\n", net_addr);
system("pause");
return 0;
}
运行结果:
Host ordered port: 0x1234
Network ordered port: 0x3412
Host ordered address: 0x12345678
Network ordered address: 0x78563412
另外需要说明的是,sockaddr_in
中保存IP地址的成员为32位整数,而我们熟悉的是点分十进制表示法,例如 127.0.0.1
,它是一个字符串,因此为了分配IP
地址,需要将字符串转换为4字节整数。inet_addr()
函数可以完成这种转换。inet_addr()
除了将字符串转换为32位整数,同时还进行网络字节序转换。请看下面的代码:
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
int main(){
char *addr1 = "1.2.3.4";
char *addr2 = "1.2.3.256";
unsigned long conv_addr = inet_addr(addr1);
if(conv_addr == INADDR_NONE){
puts("Error occured!");
}else{
printf("Network ordered integer addr: %#lx\n", conv_addr);
}
conv_addr = inet_addr(addr2);
if(conv_addr == INADDR_NONE){
puts("Error occured!");
}else{
printf("Network ordered integer addr: %#lx\n", conv_addr);
}
system("pause");
return 0;
}
运行结果:
Network ordered integer addr: 0x4030201
Error occured!
从运行结果可以看出,inet_addr()
不仅可以把IP地址转换为32位整数,还可以检测无效IP地址。注意:为 sockaddr_in
成员赋值时需要显式地将主机字节序转换为网络字节序,而通过 write()/send()
发送数据时TCP
协议会自动转换为网络字节序,不需要再调用相应的函数。
本文摘自:https://www.jianshu.com/p/68735394db7a
本文转自:https://www.workerman.net/q/7729
this
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
调用cat.jumps()
时,如果是普通函数,该方法内部的this
指向cat
;如果写成上面那样的箭头函数,使得this
指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps
箭头函数定义时的作用域就是全局作用域。
关键问题是:对象不构成单独的作用域。
// 正确的写法
let x;
({x} = {x: 1});
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
a.和堆一样存储在计算机 RAM 中。
b.在栈上创建变量的时候会扩展,并且会自动回收。
c.相比堆而言在栈上分配要快的多。
d.用数据结构中的栈实现。
e.存储局部数据,返回地址,用做参数传递。
f.当用栈过多时可导致栈溢出(无穷次(大量的)的递归调用,或者大量的内存分配)。
g.在栈上的数据可以直接访问(不是非要使用指针访问)。
h.如果你在编译之前精确的知道你需要分配数据的大小并且不是太大的时候,可以使用栈。
i.当你程序启动时决定栈的容量上限。
a.和栈一样存储在计算机RAM。
b.在堆上的变量必须要手动释放,不存在作用域的问题。数据可用 delete, delete[] 或者 free 来释放。
c.相比在栈上分配内存要慢。
d.通过程序按需分配。
e.大量的分配和释放可造成内存碎片。
f.在 C++ 中,在堆上创建数的据使用指针访问,用 new 或者 malloc 分配内存。
g.如果申请的缓冲区过大的话,可能申请失败。
h.在运行期间你不知道会需要多大的数据或者你需要分配大量的内存的时候,建议你使用堆。
i.可能造成内存泄露。