2022年7月

如果我们自建个人网站并不需要特别复杂的功能的时候,并不一定非要选择WordPress。并且WordPress真要完好确实需要一定的技术能力,尤其是后续的功能和优化需要琢磨才能使用的更好。一般普通个人网站完全可以使用Typecho,算是比较好的轻量博客程序,当然我们也看到很多个人使用Typecho做的网站也都很好。

大部分网友唯独不是特别满意Typecho的就是编辑器采用的是Markdown编辑器。毕竟官方考虑到是整个程序的体积和轻便,不过对于很多人来说不是特别喜欢这个编辑器。我们可以安装其他编辑器来丰富编辑功能,其中可以安装的是UEditor for Typecho。UEditor由百度提供的,然后有其他网友进行整合兼容到Typecho,我们一起安装看看吧。

第一、UEditor for Typecho下载和安装

下载地址:https://github.com/chanshengzhi/UEditor-for-Typecho


我们下载之后解压,然后将UEditor文件夹丢到当前Typecho主题下的usr/plugins文件夹下。

第二、UEditor for Typecho激活使用

1、暂停当前编辑器

我们需要在控制台-个人设置中关闭当前的编辑器。

2、激活编辑器

控制台-插件,找到当前安装的UEditor for Typecho插件进行激活。这个时候我们再去编辑文章看看是什么编辑器?

是不是比较丰富?

第三、UEditor for Typecho附加功能

如果我们需要将编辑器出现的静态文件,比如图片附件不在本地保存。可以配置到腾讯云COS或者又拍云。

总结,如果我们需要在Typecho较为丰富的编辑器是可以安装UEditor for Typecho插件的。


进程对应的内存空间中所包含的5种不同的数据区:

BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

以前老是为了防止变量重名,喜欢在函数里设置局部变量,感觉没啥区别,但是刷题时在main函数中定义大容量的数组时,程序有时就会报错,改成全局变量时就好了。

数组定义在函数中会占用 栈空间 ,而往往栈空间比较小,所以大数组定义在函数中会出现内存方面的问题。
但是如果将数组定义为全局变量 则分配在 数据段,则不存在所谓的内存问题!

所以遇到大容量数组,尽量还是定义为全局变量更好

我们在写程序时,既有程序的逻辑代码,也有在程序中定义的变量等数据,那么当我们的程序进行时,我们的代码和数据究竟是存放在哪里的呢?下面就来总结一下。

一、程序运行时的内存空间情况

其实在程序运行时,由于内存的管理方式是以页为单位的,而且程序使用的地址都是虚拟地址,当程序要使用内存时,操作系统再把虚拟地址映射到真实的物理内存的地址上。所以在程序中,以虚拟地址来看,数据或代码是一块块地存在于内存中的,通常我们称其为一个段。而且代码和数据是分开存放的,即不储存于同于一个段中,而且各种数据也是分开存放在不同的段中的。

下面以一个简单的程序来看一下在Linux下的程序运行空间情况,代码文件名为space.c

#include
#include

int main()
{
printf("%d\n", getpid());
while(1);
return 0;
}
这个程序非常简单,输出当前进程的进程号,然后进入一个死循环,这个死循环的目的只是让程序不退出。而在Linux下有一个目录/proc/$(pid),这个目录保存了进程号为pid的进程运行时的所有信息,其中有一个文件maps,它记录了程序执行过程中的内存空间的情况。编译运行上面的代码,其运行结果如图1所示:
20160408_uOmp[1].jpg
从上面的图中,我们可以看到这样一个简单的程序,在执行时,需要哪些库和哪些空间。上面的图的各列的意思,不一一详述,只对重要的进行说明。
第一列的是一个段的起始地址和结束地址,第二列这个段的权限,第三列段的段内相对偏移量,第六列是这个段所存放的内容所对应的文件。从上图可以看到我们的程序进行首先要加载系统的两个共享库,然后再加载我们写的程序的代码。

对于第二列的权限,r:表示可读,w:表示可写,x:表示可执行,p:表示受保护(即只对本进程有效,不共享),与之相对的是s,意是就是共享。

从上图我们可以非常形象地看到一个程序进行时的内存分布情况。下面我们将会结合上图,进行更加深入的对内存中的数据段的解说。

二、程序运行时内存的各种数据段

1.bss段
该段用来存放没有被初始化或初始化为0的全局变量,因为是全局变量,所以在程序运行的整个生命周期内都存在于内存中。有趣的是这个段中的变量只占用程序运行时的内存空间,而不占用程序文件的储存空间。可以用以下程序来说明这点,文件名为bss.c

#include

int bss_data[1024 * 1024];

int main()
{
return 0;
}

这个程序非常简单,定义一个4M的全局变量,然后返回。编译成可执行文件bss,并查看可执行文件的文件属性如图2所示:
20160408_L3I4[1].jpg
从可执行文件的大小4774B可以看出,bss数据段(4M)并不占用程序文件的储存空间,在下面的data段中,我们可以看到data段的数据是占用可执行文件的储存空间的。

在图1中,有文件名且属性为rw-p的内存区间,就是bss段。

2.data段
初始化过的全局变量数据段,该段用来保存初始化了的非0的全局变量,如果全局变量初始化为0,则编译有时会出于优化的考虑,将其放在bss段中。因为也是全局变量,所以在程序运行的整个生命周期内都存在于内存中。与bss段不同的是,data段中的变量既占程序运行时的内存空间,也占程序文件的储存空间。可以用下面的程序来说明,文件名为data.c:
#include

int data_data[1024 * 1024] = {1};

int main()
{
return 0;
}

这个程序与上面的bss唯一的不同就是全局变量int型数组data_data,其中第0个元素的值初始化为1,其他元素的值初始化成默认的0,而因为数组的地址是连续的,所以只要有一个元素在data段中,则其他的元素也必然在data段中。编 译连接成可执行文件data,并查看可执行文件的文件属性如图3所示:
20160408_wJFl[1].jpg
从可执行文件的大小来看,data段数据(data_data数组的大小,4M)占用程序文件的储存空间。

在图1中,有文件名且属性为rw-p的内存区间,就是data段,它与bss段在内存中是共用一段内存的,不同的是,bss段数据不占用文件,而data段数据占用文件储存空间。

3.rodata段
该段是常量数据段,用于存放常量数据,ro就是Read Only之意。但是注意并不是所有的常量都是放在常量数据段的,其特殊情况如下:
1)有些立即数与指令编译在一起直接放在代码段(text段,下面会讲到)中。
2)对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份。
3)有些系统中rodata段是多个进程共享的,目的是为了提高空间的利用率。

在图1中,有文件名的属性为r--p的内存区间就是rodata段。可见他是受保护的,只能被读取,从而提高程序的稳定性。

4.text段
text段就是代码段,用来存放程序的代码(如函数)和部分整数常量。它与rodata段的主要不同是,text段是可以执行的,而且不被不同的进程共享。

在图1中,有文件名且属性为r-xp的内存区间就是text段。就如我们所知道的那样,代码段是不能被写的。

5.stack段
该段就是栈段,用来保存临时变量和函数参数。程序中的函数调用就是以栈的方式来实现的,通常栈是向下(即向低地址)增长的,当向栈中push一个元素,栈顶指针就会向低地址移动,当从栈中pop一个元素,栈顶指针就会向高地址移动。栈中的数据只在当前函数或下一层函数中有效,当函数返回时,这些数据自动被释放,如果继续对这些数据进行访问,将发生未知的错误。通常我们在程序中定义的不是用malloc系统函数或new出来的变量,都是存放在栈中的。例如,如下函数:
void func()
{
int a = 0;
int *n_ptr = malloc(sizeof(int));
char *c_ptr = new char;
}

整型变量a,整型指针变量n_ptr和char型指针变量c_ptr,都存放在栈段中,而n_ptr和c_ptr指向的变量,由于是malloc或new出来的,所以存放在堆中。当函数func返回时,a、n_ptr、c_ptr都会被释放,但是n_ptr和c_ptr指向的内存却不会释放。因为它们是存在于堆中的数据。

在图1中,文件名为stack的内存区间即为栈段。

6.heap段
heap(堆)是最自由的一种内存,它完全由程序来负责内存的管理,包括什么时候申请,什么时候释放,而且对它的使用也没有什么大小的限制。在C/C++中,用alloc系统函数和new申请的内存都存在于heap段中。

以上面的程序为例,它向堆申请了一个int和一个char的内存,因为没有调用free或delete,所以当函数返回时,堆中的int和char变量并没有释放,造成了内存泄漏。

由于在图1所对应的代码中没有使用alloc系统函数或new来申请内存,所以heap段并没有在图1中显示出来,所以以下面的程序来说明heap段的位置,代码文件为heap.c,代码如下:
#include
#include
#include

int main()
{
int *n_ptr = malloc(sizeof(int));
printf("%d\n", getpid());
while(1);
free(n_ptr);
return 0;
}

查看其运行时内存空间分布如下:20160408_gHuN[1].jpg
可以看到文件名为heap的内存区间就是heap段。从上图,也可以看出,虽然我们只申请4个字节(sizeof(int))的空间,但是在操作系统中,内存是以页的方式进行管理的,所以在分配heap内存时,还是一次分配就为我们分配了一个页的内存。注:无论是图1,还是上图,都有一些没有文件名的内存区间,其实没用文件名的内存区间表示使用mmap映射的匿名空间
转载于:https://my.oschina.net/jingxia/blog/697516

#include
#include

class CMyClass
{
public:
CMyClass() { printf(" Constructor\n"); }
~CMyClass() { printf(" Destructor\n"); }
};
CMyClass theObject1;
int main()
{
CMyClass theObject;
::ExitThread(0);
//exit(0);

// 在这个函数的结尾,编译器会自动添加一些必要的代码,
// 来调用theObject的析构函数
return 0;

}

exit(0):可以看到只析构了一个对象,而另外一个未被析构,其实没被析构的对象是局部对象,前面提到exit函数主要任务就是负责析构全局对象和变。

ExitProcess: 局部对象和全局对象都没被析构,因为调用了ExitProcess进程直接结束,而没有调用启动函数中的exit函数,所以全局对象也没被析构。

TerminateProcess: 函数的实际作用跟ExitProcess函数差不多,只不过,此函数可用来终止当前进程之外的另外一个其它进程。

程序中报 "char *" 类型的实参与 "LPWSTR" 类型的形参不兼容C/C++(167) 错误
#include
#include

int main(int argc, char* argv[])
{
char szCommandLine[] = "cmd";
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;

si.dwFlags = STARTF_USESHOWWINDOW; // 指定wShowWindow成员有效
si.wShowWindow = TRUE; // 此成员设为TRUE的话则显示新建进程的主窗口,
// 为FALSE的话则不显示
BOOL bRet = ::CreateProcess (
NULL, // 不在此指定可执行文件的文件名
szCommandLine, // 命令行参数
NULL, // 默认进程安全性
NULL, // 默认线程安全性
FALSE, // 指定当前进程内的句柄不可以被子进程继承
CREATE_NEW_CONSOLE, // 为新进程创建一个新的控制台窗口
NULL, // 使用本进程的环境变量
NULL, // 使用本进程的驱动器和目录
&si,
&pi);

if(bRet)
{
// 既然我们不使用两个句柄,最好是立刻将它们关闭
::CloseHandle (pi.hThread);
::CloseHandle (pi.hProcess);

printf(" 新进程的进程ID号:%d \n", pi.dwProcessId);
printf(" 新进程的主线程ID号:%d \n", pi.dwThreadId);
}
return 0;
}

解决办法
方法一、把工程设置里去掉UNICODE宏定义

项目->XXX属性->配置属性->常规->字符集 , 由使用Unicode字符集 改为 使用多字节字符集

方法二、在程序的开头加上 #undef UNICODE