全程剖析C语言中堆和栈的区别

1.申请方式
(1)栈(satck):由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。
(2)堆(heap):需程序员自己申请(调用malloc,realloc,calloc),并指明大小,并由程序员进行释放。容易产生memory leak.
eg:

但是,p本身是在栈中。

Continue reading “全程剖析C语言中堆和栈的区别”

C语言实现内存池

什么是内存池,这里简单介绍一下(不做详细说明),内存池技术是一种用于分配大量大小相同的小对象的技术,通过该技术可以极大加快内存分配/释放过程。其原理是先申请一大块内存,然后分成若干个大小相等的小块,用链表的方式将这些小块链在一起,当开发人员需要使用内存时(分配),从链表头取下一块返回给开发人员使用;当开发人员使用完毕后(释放),再将这块内存重新挂回链表尾。

这样操作的好处有如下三点:
1、提高分配和释放的效率;
2、避免开发人员忘记释放内存造成内存泄露;
3、减少内存占用(频繁的malloc是很占内存空间的,至于为什么我就不说了,可以到网上搜索内存管理相关的内容);
Continue reading “C语言实现内存池”

深入理解PHP原理之Opcodes

Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL,举个例子,比如你写下了如下的PHP代码:

PHP执行这段代码会经过如下4个步骤(确切的来说,应该是PHP的语言引擎Zend)

1. Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)
2. Parsing, 将Tokens转换成简单而有意义的表达式
3. Compilation, 将表达式编译成Opocdes
4. Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

附记:现在有的Cache比如APC,可以使得PHP缓存住Opcodes,这样,每次有请求来临的时候,就不需要重复执行前面3步,从而能大幅的提高PHP的执行速度。
Continue reading “深入理解PHP原理之Opcodes”

结构体数组可变,地址连续(转)

若要一个结构体中的数组是可变的,应该这样写

 

struct _example

{

   int size;         //数组的大小

   char* array;    //数组的地址

}example

 

example tmp;

tmp.size = 100;

tmp.array = (char*)malloc(tmp.size);

 

这样结构体里的数组的大小是动态分配的,但是这样分配的地址不是连续的,也就是说array指向的这个数组(不是array的地址)不是接在tmp.size地址的后面,这样有时候会不方便,比如说用memcpy去从tmp首地址开始拷贝,只能拷贝到size和array的值(即数组的首地址),如果想要得到数组里的数据就还要用memcpy从取array的值再来拷贝一次,这样就很麻烦,特别是在socket编程的时候,每次传出的数据都是  大小+数据 的模式,如果是这样写的结构体,就得要调用2次传输函数,但是下面这种写法可以解决这个麻烦。。。

 

struct _example

{

   int size;         //数组的大小

   char array[1];    //数组的地址

}example

 

int nLen = 100+4;

example* tmp = (example*)malloc(nLen);

tmp.size = 100;

 

这样其实是一种取巧的方法,为tmp这个指针分配一个大于example结构体的内存,要多大就看你需要的数组要多大了,这样多余的内存就排在了array后面,array的“规定”大小只有1,但是就算array[1],array[2]array[3]…array[99]它都没有越界或者访问到了非法地址,所以可以放心的往后面添加数据,而这块内存是由一次malloc产生的,所以数据块一定是连续的,这样如果要复制tmp里的内容就可以只用memcpy就可以做好了。

共享内存和信号量

共享内存:

可以通过ipcs -lm命令查看目前系统共享内存的参数限制:

# ipcs -lm

—— Shared Memory Limits ——–

max number of segments = 4096

max seg size (kbytes) = 1048576

max total shared memory (pages) = 2097152

min seg size (bytes) = 1

这里涉及到3个于共享内存相关的参数:SHMMAXSHMMNISHMALL


SHMMAX

含义:每个共享内存段的最大字节数

设置:比SGA略大

查看:cat /proc/sys/kernel/shmmax

$ cat /proc/sys/kernel/shmmax

1073741824

修改:

sysctl -w kernel.shmmax=1073741824

echo “kernel.shmmax = 1073741824” >> /etc/sysctl.conf


SHMMIN

含义:每个共享内存段的最小字节数


SHMSEG

含义:每进程最大共享内存段数量


SHMMNI

含义:系统范围最大共享内存段的数量

设置:至少4096

查看:cat /proc/sys/kernel/shmmni

# cat /proc/sys/kernel/shmmni

4096

修改:

# sysctl -w kernel.shmmni=4096

# echo “kernel.shmmni = 4096” >> /etc/sysctl.conf


SHMALL

含义:系统中共享内存页总数

设置:至少ceil(shmmax/PAGE_SIZE)ORACLE DOC 默认值:2097152*4096=8GB

查看:cat /proc/sys/kernel/shmall

$ getconf PAGE_SIZE

4096

# cat /proc/sys/kernel/shmall

2097152

修改:

# sysctl -w kernel.shmall=2097152

# echo kernel.shmall = 2097152 >> /etc/sysctl.conf



信号量:

当前系统信号量限制:

$ ipcs -ls

—— Semaphore Limits ——–

max number of arrays = 128

max semaphores per array = 250

max semaphores system wide = 32000

max ops per semop call = 32(设置成100比较好)

semaphore max value = 32767


SEMMNI

含义:信号灯标识符的最小数量(也就是说,套)

设置:最少128


SEMMSL

含义:每套信号灯最小信号灯数量

设置:最小250;对于processes参数设置较大的系统建议设置为processes+10

一套信号灯里可以有多少信号灯,对于Postgres而言应该至少是 17


SEMMNS

含义:linux系统中信号量最大个数

设置:至少32000SEMMNI *SEMMSL


SEMOPM

含义:semop系统调用允许的信号量最大个数

设置:至少100;或者等于SEMMSL

查看信号量设置:cat /proc/sys/kernel/sem


SEMVMX
信号灯的最大值(semaphore max value = 32767

orderSEMMSL, SEMMNS, SEMOPM, SEMMNI

$ cat /proc/sys/kernel/sem

250    32000    100    128

修改:

sysctl -w kernel.sem=”250 32000 100 128

echo kernel.sem = 250 32000 100 128 >> /etc/sysctl.conf

ORACLE提供了sysresv工具管理共享内存以及信号量,操作系统级别可以通过ipcs管理。

kernel.shmall = 2097152 # 可以使用的共享内存的总量,单位:页。

kernel.shmmax = 2147483648 # 最大单个共享内存段大小。取物理内存大小的一半,单位为字节

kernel.shmmni = 4096 # 整个系统共享内存段的最大数目。

kernel.sem = 250 32000 100 128 # 每个信号对象集的最大信号对象数;系统范围内最大信号对象数;每个信号对象支持的最大操作数;系统范围内最大信号对象集数。

fs.file-max = 65536 # 系统中所允许的文件句柄最大数目。

net.ipv4.ip_local_port_range = 1024 65000 # 应用程序可使用的IPv4端口范围。

net.core.rmem_default = 1048576 # 套接字接收缓冲区大小的缺省值

net.core.rmem_max = 1048576 # 套接字接收缓冲区大小的最大值

net.core.wmem_default = 262144 # 套接字发送缓冲区大小的缺省值

net.core.wmem_max = 262144 # 套接字发送缓冲区大小的最大值

Linux信号处理

1.信号集概念

信号集是一个能表示多个信号的数据类型,sigset_t set ;set即一个信号集。既然是一个集合,就需要对集合进行添加/删除等操作。

int sigemptyset(sigset_t *set); 将set集合置空
int sigfillset(sigset_t *set); 将所有信号加入set集合
int sigaddset(sigset_t *set,int signo); 将signo信号加入到set集合
int sigdelset(sigset_t *set,int signo); 从set集合中移除signo信号
int sigismember(const sigset_t *set,int signo); signo判断信号是否存在于set集合中


代码举例:

class=”lang:cpp decode:true “ view plaincopyprint?

  1. <span style=“font-size:16px;color:#000000;”>#include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<sys/types.h>  
  4. #include<sys/stat.h>  
  5. #include<signal.h>  
  6.   
  7. int main()  
  8. {  
  9.  sigset_t sigset;  
  10.  sigfillset(&sigset);/*填充所有信号*/  
  11.  if(sigismember(&sigset,SIGINT))/*判断SIGINT*/  
  12.  printf(“SIGINT exist in signal_set!\n”);  
  13.  if(sigismember(&sigset,SIGTERM))  
  14.   printf(“SIGTERM exist in signal_set!\n”);  
  15.  if(sigismember(&sigset,SIGABRT))  
  16.   printf(“SIGABRT exist in signal_set!\n”);  
  17.  if(sigdelset(&sigset,SIGINT)<0)/*移除SIGINT*/  
  18.   perror(“del error\n”);  
  19.  else  
  20.   printf(“SIGINT have been removed!\n”);  
  21.  if(sigismember(&sigset,SIGINT))/*再次判断*/  
  22.   printf(“SIGINT exist in signal_set!\n”);  
  23.  else  
  24.   printf(“SIGINT not exist in signal_set!\n”);  
  25. }  
  26.   
  27. </span>  

 

输出:

 $ ./sigset
    SIGINT exist in signal_set!
 SIGTERM exist in signal_set!
 SIGABRT exist in signal_set!
 SIGINT have been removed!
 SIGINT not exist in signal_set!

2. 信号集的使用

   定义信号集->设置信号屏蔽位->定义信号处理函数->检测信号
   <1>使用1中的函数即可完成信号集的定义,之后是
   <2>设置信号屏蔽位
   其作用为设置某个进程需要屏蔽的信号

   Int sigprocmask(int how,const sigset_t *set,sigset_t *oset);

参数

 How 指示如何修改屏蔽信号
 Set是一个非空指针时,根据how修改屏蔽信号
 Oset是一个非空指针时,存放当前屏蔽信号集
 若set为NULL,不改变该进程的信号屏蔽字,how也无意义

 How的取值:

   S I G B L O C K
   该进程新的信号屏蔽字是其当前信号屏蔽字和s e t指向信号集的并集。s e t包含了我们希望阻塞的附加信号

   S I G U N B L O C K
   该进程新的信号屏蔽字是其当前信号屏蔽字和s e t所指向信号集的交集。s e t包含了我们希望解除阻塞的信号

   S I G S E T M A S K
   该进程新的信号屏蔽是s e t指向的值

   举例

class=”lang:cpp decode:true “ view plaincopyprint?

  1. <span style=“font-size:16px;color:#000000;”>#include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<sys/types.h>  
  4. #include<sys/stat.h>  
  5. #include<signal.h>  
  6.   
  7. /*sigprocmsk的使用*/  
  8.   
  9. void msg(int signo)  
  10. {  
  11.  if(signo==SIGINT)  
  12.   printf(“Get SIGINT!\n”);  
  13.  else  
  14.   printf(“Get SIGQUIT!\n”);  
  15. }  
  16.   
  17. int main()  
  18. {  
  19.  sigset_t sigset,oset;/*sigset存放屏蔽信号,oset保存当前屏蔽信号*/  
  20.  sigemptyset(&sigset);/*清空信号集*/  
  21.  sigaddset(&sigset,SIGINT);/*添加SIGINT信号,信号集中仅有SIGINT*/  
  22.  sigprocmask(SIG_BLOCK,&sigset,&oset);/*加入屏蔽信号*/  
  23.   
  24.  signal(SIGINT,msg);  
  25.  signal(SIGQUIT,msg);  
  26.   
  27.  sleep(2);  
  28.   
  29.  raise(SIGINT);/*发送SIGINT信号*/  
  30.  raise(SIGQUIT);   
  31.   
  32.  return 0;  
  33. }   
  34.   
  35. </span>  

  输出

  Get SIGQUIT!

 <3>定义信号处理函数

  s i g a c t i o n函数的功能是检查或修改(或两者)与指定信号相关联的处理动作。此函数取代了U N I X早期版本使用的s i g n a l函数
  Int sigaction(int signo,const struct sigaction *act,struct sigaction *oact);

  参数:signo 要检测或修改动作的信号量
     Act 非空时,表示要修改的动作
     Oact非空时,返回处理该信号的原先动作

     结构体sigaction如下:

      struct sigaction {
      void (*sa_handler)();/*处理函数或SIG_IGN(忽略)或SIG_DFL(默认)*/
       sigset_t sa_mask; /*处理函数过程中被阻塞*/
     int sa_flags; /*标志位,对信号进程处理选项*/
     } ;

  举例

class=”lang:cpp decode:true “ view plaincopyprint?

  1. <span style=“font-size:16px;color:#000000;”>#include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<sys/types.h>  
  4. #include<sys/stat.h>  
  5. #include<signal.h>  
  6.   
  7. void msg(int signo)  
  8. {  
  9.  if(signo==SIGINT)  
  10.   printf(“Get SIGINT!\n”);  
  11. }  
  12.   
  13. int main()  
  14. {  
  15.  sigset_t sigset,oset;/*sigset存放屏蔽信号,oset保存当前屏蔽信号*/  
  16.  struct sigaction action1,action2;/*信号处理*/  
  17.   
  18.  action1.sa_handler=msg;  
  19.  sigaction(SIGINT,&action1,&action2);  
  20.   
  21.  sleep(2);  
  22.   
  23.  raise(SIGINT);/*发送SIGINT信号*/  
  24.  return 0;  
  25. }   
  26. </span>  

  输出:

   Get SIGINT

 <4>检测被搁置信号

  Int sigpending(sigset_t *set);
  返回对于调用进程被阻塞不能递送和当前未决的信号集。该信号集通过s e t参数返回。


原文链接:http://linux.chinaitlab.com/command/857706.html

 

附:linux信号

信号是一种进程间通信的方法,它应用于异步事件的处理。信号的实质是一种软中断,它被发送给一个正在被执行的进程以通知进程有某一特定事件发生了。
一、信号含义

 信号拥有自己特定的名字,均以SIG开始,它们在头文件中被定义为一个正整数,这些正整数被称为信号编号(signal number)。
 以下为各个信号的具体含义:

 1.         SIGHUP:当终端发现断线情况时发送给与控制终端相连的控制进程的信号,或控制进程运行结束时发出的信号。它通常用来通知守护进程重新读取系统配置文件。
 2.         SIGINT:进程中断信号,可以用来中断一个正在运行的进程。通常是从终端输入的中断指令,如Ctrl+C键或Delete键。
 3.         SIGQUIT:用于中断前台进程组中的所有进程的信号。由终端输入的退出指令Ctrl+\所产生。这一信号在终端进程的同时,还将产生一个core文件。
 4.         SIGILL:执行非法硬件指令时产生的错误。
 5.         SIGTRAP:跟踪陷阱信号。
 6.         SIGIOT:I/O错误信号。
 7.         SIGBUS:系统总线错误时产生的信号。
 8.         SIGFPE:浮点运算中发生溢出错误时产生的信号。
 9.         SIGKILL:可用于终止任何一个进程的信号,只能由系统管理员发出,是不可捕捉和被忽略的信号之一。
 10.     SIGUSR1:用于用户自定义的预留信号。可由用户在应用程序中自行定义。
 11.     SIGSEGV:使用非法内存地址所产生的信号。
 12.     SIGUSR2:同SIGUSR1。
 13.     SIGPIPE:当对一个读进程已经运行结束的管道执行写操作时产生的信号。
 14.     SIGALRM:由alarm函数设定的时间段终止时,会产生此信号。
 15.     SIGTERM:调用kill(1)命令时缺省产生的信号。
 16.     SIGCHLD:当一个子进程结束或中断时,用于通知其父进程的信号。必要时,父进程可以通过这一信号来了解子进程的状态变化及结束状态等信息。但在大多数情况下,这一信号将被忽略。
 17.     SIGCONT:是使已被中断的进程继续执行的信号。当此信号为某一特定进程产生后,如果此时该进程并没有被中断,将不会有任何操作发生;但如果该进程是一中断了的进程,即使SIGCONT信号被阻塞或被忽略,此进程也将会继续进行。
 18.     SIGSTOP:中断进程的信号。它是一个作业信号,同时也是不可被捕捉和被忽略的信号之一。
 19.     SIGTSTP:交互式的中断信号。通常是在输入中断键Ctrl+Z时,由终端驱动器所产生。
 20.     SIGTTIN:当一个后台进程需要从终端读取数据时,终端驱动器产生的信号。当读取数据的进程忽略或阻塞这个信号,或者读取数据的进程所在的进程组是孤立进程组时,信号不会产生,并且读操作会发生错误返回,将errno置EIO。
 21.     SIGTTOU:当一个后台进程需要向终端写入数据时,终端驱动器产生的信号。当写入数据的进程忽略或阻塞这个信号,或者写数据的进程所在的进程组是孤立进程组时,信号不会产生,并且写操作会发生错误返回,将errno置EIO。与SIGTTIN不同的是,进程可以选择对控制终端进行后台写。如果后台写不被允许则同SIGTTIN信号一样。
 22.     SIGURG:套接字上出现出现紧急情况时产生的信号。
 23.     SIGXCPU:超出CPU时间限制时产生的信号。
 24.     SIGXFSZ:超出文件大小时产生的信号。
 25.     SIGVTALRM:虚拟定时器报警信号。
 26.     SIGPROF:Profiling定时器报警信号。
 27.     SIGWINCH:终端窗口改变时产生的信号。
 28.     SIGIO:表示某个特定文件描述符上可以进行I/O操作的信号。
 29.     SIGPWR:电源失效信号。
 30.     SIGABRT:调用abort函数时产生的信号,将会使进程非正常结束。
 31.     SIGEMT:实现性定义硬件错误发生时产生的信号。

二、信号的处理

 信号是用于处理异步事件的发生的。在一个进程执行过程中,如果有信号被发送到该进程,则该进程将按预先设定好的处理方法进行相应处理。总体上来讲,当信号发生时,进程所采取的处理方法可以分为两种:

 1.         捕捉信号。当某个信号被发送到一个正在运行的进程时,该进程及对此特定信号注册相应的信号处理函数,以完成所需处理。也就是说,在编写程序代码时,对需要进行捕捉处理的信号给出相应的处理程序代码。一旦接收到此信号,则通知系统调用相应信号处理函数做出处理。对应于每一个信号,系统中都有相应的缺省处理函数(通常为终止进程)。可以设定进程在信号发生时使用缺省处理函数进行处理。
 2.         忽略信号。当不希望接收到的信号对进程的执行产生影响,而让进程继续进行时,可以忽略该信号。进程将继续进行而不对信号进行任何处理。


原文链接:http://hi.baidu.com/xiboliya/blog/item/f60153ee5a5fa8f3b2fb95b6.html

Linux线程-sysconf系统变量

使用sysconf( )

了解系统的线程资源限制是使得应用程序恰当地管理它们的关键。前面已经讨论了利用系统资源的示例。当设置线程的栈大小时,最小值为PTHREAD_MIN_STACK。栈大小不应当低于由pthread_attr_getstacksize( )返回的默认栈大小的最小值。每个进程的最大线程数决定了能够为每个进程创建的worker线程的上限。函数sysconf( )用于返回可配置系统限制或选项的当前值。系统中定义了同线程、进程和信号量相关的多个变量和常量。在表6-8中,列出了部分变量和常量。

表6-8

    

名字值(Name Value)

    

_SC_THREADS

_POSIX_THREADS

支持线程

_SC_THREAD_ATTR_

STACKADDR

_POSIX_THREAD_ATTR_

STACKADDR

支持线程栈地址属性

_SC_THREAD_ATTR_

STACKSIZE

_POSIX_THREAD_ATTR_

STACKSIZE

支持线程栈大小属性

_SC_THREAD_STACK_MIN

PTHREAD_STACK_MIN

线程栈存储区的

最小大小,以字节为单位


(续表)

    

名字值(Name Value)

    

_SC_THREAD_THREADS_MAX

PTHREAD_THREADS_MAX

每个进程的

最大线程数

_SC_THREAD_KEYS_MAX

PTHREAD_KEYS_MAX

每个进程关键

字的最大数目

_SC_THREAD_PRIO_INHERIT

_POSIX_THREAD_PRIO_

INHERIT

支持优先

级继承选项

_SC_THREAD_PRIO

_POSIX_THREAD_PRIO_

支持线程

优先级选项

_SC_THREAD_PRIORITY_

SCHEDULING

_POSIX_THREAD_PRIORITY_

SCHEDULING

支持线程优

先级调度选项

_SC_THREAD_PROCESS_

SHARED

_POSIX_THREAD_PROCESS_

SHARED

支持进程共享同步

_SC_THREAD_SAFE_

FUNCTIONS

_POSIX_THREAD_SAFE_

FUNCTIONS

支持线程安全函数

_SC_THREAD_DESTRUCTOR_

ITERATIONS

_PTHREAD_THREAD_

DESTRUCTOR_ITERATIONS

决定在线程退

出时尝试销毁

线程特定数据

的尝试次数

_SC_CHILD_MAX

CHILD_MAX

每个UID允许

的最大进程数目

_SC_PRIORITY_SCHEDULING

_POSIX_PRIORITY_

SCHEDULING

支持进程调度

_SC_REALTIME_SIGNALS

_POSIX_

REALTIME_SIGNALS

支持实时信号

_SC_XOPEN_REALTIME_

THREADS

_XOPEN_

REALTIME_THREADS

支持X/Open

POSIX实时

线程特性组

_SC_STREAM_MAX

STREAM_MAX

决定进程能够

打开的流的数目

_SC_SEMAPHORES

_POSIX_SEMAPHORES

支持信号量

_SC_SEM_NSEMS_MAX

SEM_NSEMS_MAX

决定线程能

够拥有的信号

量的最大数目

_SC_SEM_VALUE_MAX

SEM_VALUE_MAX

决定信号量的最大值

_SC_SHARED_MEMORY_

OBJECTS

_POSIX_SHARED_MEMORY_

OBJECTS

支持共享内存对象

 

下面是调用sysconf( )的示例:

代码中将sysconf( )返回的_SC_THREAD_STACK_MIN的值同PTHREAD_STACK_MIN这个常量值进行了比较。

int epoll_create(int size) size参数的含义

 Since Linux 2.6.8, the size argument is unused.  (The kernel dynamically sizes
the required data structures without needing this initial hint.)

http://www.kernel.org/doc/man-pages/online/pages/man2/epoll_create.2.html



DoxyGen常用标记

Doxygen可以为C++, C, Java, IDL (Corba and Microsoft flavors) PHP和C#生成文档 


大致用途有三:
1. 可以生成一个在线html文档或者一个离线的LATEX格式文档也支持RTF(MS-Word) PostScript, hyperlinked PDF, compressed HTML, 和Unix man pages多种格式生成。文档直接由源码生成,这使得保持文档和代码一致性更加轻松。 


2. 可以配置doxygen从无文档的源码中提取代码结构。这就便于在大型源码中迅速上路。也可以将这些不同元素间的关系使用图形表达出来,包括依赖图,继承图和collaboration图,这些都是自动生成的。 


3. 甚至可以使用它来生成平常的文档,例如手册

标记以“\”开头,或是一个“@”(使用JavaDoc风格),后面是命令名和一或多个参数。

这些标记都是写在注释块中的,详见随邮件的例子(_common\obj.h)。

说明类型:
分为摘要说明和详细说明
   \brief 后紧跟摘要说明,也可以直接使用“//!”开始注释。
  
详细说明:在摘要说明后,间隔一行书写,见实例。
  
基本结构的说明标记:
\file [file name] 写文件的说明, 后跟此文件的文件名;另起一行书写此文件的说明文字。
\class [class name] 写类的说明,后跟类名;另起一行书写类的说明文字。


用于函数内部的说明标记:
这些标记会在函数的详细说明中使用不同的字体和格式,突出显示。
\param [param name] 写函数参数的说明,后跟参数名;紧跟参数的说明文字。
\return     写函数返回值得说明,后紧跟返回值得说明。
\warning    警告,后紧跟警告的内容。
\remarks    评论,后紧跟评论的内容。

可单独生成主题的说明标记:
\todo     被此标记说明的代码会在Todo列表中出现。
\bug     被此标记说明的代码会在Bug列表中出现。
\test     被此标记说明的代码会在Test列表中出现。
\deprecated    被此标记说明的代码会在deprecated列表中出现。

\defgroup [group name] [brief] 定义一个代码块,可对代码块写说明;注意group name必须是唯一的;
           另起一行写详细说明
   \{ 代码块开始
   \} 代码块技术


格式化说明标记:
– 主题
   -# 子标题1\n
    说明
   -# 子标题2\n
    说明
生成文档中可显示为编号的列表
注意:在注释中,可完全使用html格式化标记。

@author           作者
@brief              摘要
@version          版本号
@date              日期
@file                文件名,可以默认为空,DoxyGen会自己加
@class             类名
@param            函数参数
@return            函数返回值描述
@exception       函数抛异常描述
@warning         函数使用中需要注意的地方
@remarks        备注
@see               see also字段
@note             brief下空一行后的内容表示详细描述,但也可以不空行用note表示
@par               开始一个段落,段落名称描述由你自己指定,比如可以写一段示例代码
@code             引用代码段
@endcode       引用代码段结束
@pre                函数前置条件,比如对输入参数的要求
@post             函数后置条件,比如对系统状态的影响或返回参数的结果预期

不太常用的标记:

@defgroup       模块名
@name             分组名
@{                   模块开始
@}                   模块结束
@deprecated     今后可能将被废弃或已经有替代品的函数
@since             从哪个版本后开始有这个函数的
@todo              被标记的代码会在ToDo列表中出现
@bug               被标记的代码会在Bug列表中出现
@test               被标记的代码会在Test列表中出现
–                      一级项目符号
-#                   二级项目符号

QT md5

MD5中的MD代表Message Digest,就是信息摘要的意思,不过这个信息摘要不是信息内容的缩写,而是根据公开的MD5算法对原信息进行数学变换后得到的一个128位(bit)的特征码。

这个特征码有如下特性,首先它不可逆,例如我有一段秘密的文字如:”My Secret Words”,经算法变换后得到MD5码(b9944e9367d2e40dd1f0c4040d4daaf7),把这个码告诉其他人,他们根据这个MD5码是没有系统的方法可以知道你原来的文字是什么的。

其次,这个码具有高度的离散性,也就是说,原信息的一点点变化就会导致MD5的巨大变化,例如”ABC” MD5(902fbdd2b1df0c4f70b4a5d23525e932)和”ABC “(多了一空格)MD5(12c774468f981a9487c30773d8093561)差别非常大,而且之间没有任何关系,也就是说产生的MD5码是不可预测的。

最后由于这个码有128位那么长,所以任意信息之间具有相同MD5码的可能性非常之低,通常被认为是不可能的。 

所以一般认为MD5码可以唯一地代表原信息的特征,通常用于密码的加密存储,数字签名,文件完整性验证等。

一:

在src 里找到md5的 h 和cpp

#include “md5.cpp”

    MD5Context md5ctx;

    MD5Init(&md5ctx);
    QString test=”yjy”;
    QByteArray arr=test.toAscii();
    MD5Update(&md5ctx,(const md5byte *)arr.data(),arr.size());
    md5byte ans[16];
    MD5Final(&md5ctx,ans);
    for (int i=0;i<16;i++){
        qDebug(“%X”,ans[i]);
    }

二:

QT中,提供了QCryptographicHash类,很方便的实现的字符串到md5/md4/sha1的转换,

可以通过两种方法实现:

QString pwd=”123456″;  
QString md5;  
QByteArray ba,bb;  
QCryptographicHash md(QCryptographicHash::Md5);  
ba.append(pwd);  
md.addData(ba);  
bb = md.result();  
md5.append(bb.toHex());  
QString pwd=”123456″;
QString md5;
QByteArray ba,bb;
QCryptographicHash md(QCryptographicHash::Md5);
ba.append(pwd);
md.addData(ba);
bb = md.result();
md5.append(bb.toHex()); 

qDebug()<<md5;

第二种方法比较直接:

QString md5;  
QString pwd=”123456″;  
QByteArray bb;  
bb = QCryptographicHash::hash ( pwd.toAscii(), QCryptographicHash::Md5 );  
md5.append(bb.toHex());