红黑树(三)之 Linux内核中红黑树的经典实现
概要
前面分别介绍了红黑树的理论知识 以及 通过C语言实现了红黑树。本章继续会红黑树进行介绍,下面将Linux 内核中的红黑树单独移植出来进行测试验证。若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章。
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3624202.html
更多内容:数据结构与算法系列 目录
(01) 红黑树(一)之 原理和算法详细介绍
(02) 红黑树(二)之 C语言的实现
(03) 红黑树(三)之 Linux内核中红黑树的经典实现(04) 红黑树(四)之 C++的实现(05) 红黑树(五)之 Java的实现(06) 红黑树(六)之 参考资料
Linux内核中红黑树(完整源码)
红黑树的实现文件(rbtree.h)
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de> This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA linux/include/linux/rbtree.h To use rbtrees you'll have to implement your own insert and search cores.
This will avoid us to use callbacks and to drop drammatically performances.
I know it's not the cleaner way, but in C (not in C++) to get
performances and genericity... Some example of insert and search follows here. The search is a plain
normal search over an ordered tree. The insert instead must be implemented
in two steps: First, the code must insert the element in order as a red leaf
in the tree, and then the support library function rb_insert_color() must
be called. Such function will do the not trivial work to rebalance the
rbtree, if necessary. -----------------------------------------------------------------------
static inline struct page * rb_search_page_cache(struct inode * inode,
unsigned long offset)
{
struct rb_node * n = inode->i_rb_page_cache.rb_node;
struct page * page; while (n)
{
page = rb_entry(n, struct page, rb_page_cache); if (offset < page->offset)
n = n->rb_left;
else if (offset > page->offset)
n = n->rb_right;
else
return page;
}
return NULL;
} static inline struct page * __rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
struct rb_node * parent = NULL;
struct page * page; while (*p)
{
parent = *p;
page = rb_entry(parent, struct page, rb_page_cache); if (offset < page->offset)
p = &(*p)->rb_left;
else if (offset > page->offset)
p = &(*p)->rb_right;
else
return page;
} rb_link_node(node, parent, p); return NULL;
} static inline struct page * rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct page * ret;
if ((ret = __rb_insert_page_cache(inode, offset, node)))
goto out;
rb_insert_color(node, &inode->i_rb_page_cache);
out:
return ret;
}
-----------------------------------------------------------------------
*/ #ifndef _SLINUX_RBTREE_H
#define _SLINUX_RBTREE_H #include <stdio.h>
//#include <linux/kernel.h>
//#include <linux/stddef.h> struct rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} /* __attribute__((aligned(sizeof(long))))*/;
/* The alignment might seem pointless, but allegedly CRIS needs it */ struct rb_root
{
struct rb_node *rb_node;
}; #define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
#define rb_color(r) ((r)->rb_parent_color & 1)
#define rb_is_red(r) (!rb_color(r))
#define rb_is_black(r) rb_color(r)
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->rb_parent_color = (rb->rb_parent_color & ) | (unsigned long)p;
}
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~) | color;
} #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \
const typeof( ((type *))->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );}) #define RB_ROOT (struct rb_root) { NULL, }
#define rb_entry(ptr, type, member) container_of(ptr, type, member) #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) static inline void rb_init_node(struct rb_node *rb)
{
rb->rb_parent_color = ;
rb->rb_right = NULL;
rb->rb_left = NULL;
RB_CLEAR_NODE(rb);
} extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *); typedef void (*rb_augment_f)(struct rb_node *node, void *data); extern void rb_augment_insert(struct rb_node *node,
rb_augment_f func, void *data);
extern struct rb_node *rb_augment_erase_begin(struct rb_node *node);
extern void rb_augment_erase_end(struct rb_node *node,
rb_augment_f func, void *data); /* Find logical next and previous nodes in a tree */
extern struct rb_node *rb_next(const struct rb_node *);
extern struct rb_node *rb_prev(const struct rb_node *);
extern struct rb_node *rb_first(const struct rb_root *);
extern struct rb_node *rb_last(const struct rb_root *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
struct rb_node ** rb_link)
{
node->rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL; *rb_link = node;
} #endif /* _LINUX_RBTREE_H */
红黑树的实现文件(rbtree.c)
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
(C) 2002 David Woodhouse <dwmw2@infradead.org> This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA linux/lib/rbtree.c
*/ #include "rbtree.h" static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
{
struct rb_node *right = node->rb_right;
struct rb_node *parent = rb_parent(node); if ((node->rb_right = right->rb_left))
rb_set_parent(right->rb_left, node);
right->rb_left = node; rb_set_parent(right, parent); if (parent)
{
if (node == parent->rb_left)
parent->rb_left = right;
else
parent->rb_right = right;
}
else
root->rb_node = right;
rb_set_parent(node, right);
} static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
{
struct rb_node *left = node->rb_left;
struct rb_node *parent = rb_parent(node); if ((node->rb_left = left->rb_right))
rb_set_parent(left->rb_right, node);
left->rb_right = node; rb_set_parent(left, parent); if (parent)
{
if (node == parent->rb_right)
parent->rb_right = left;
else
parent->rb_left = left;
}
else
root->rb_node = left;
rb_set_parent(node, left);
} void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent; while ((parent = rb_parent(node)) && rb_is_red(parent))
{
gparent = rb_parent(parent); if (parent == gparent->rb_left)
{
{
register struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
} if (parent->rb_right == node)
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
} rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(gparent, root);
} else {
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
} if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
} rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
} rb_set_black(root->rb_node);
} static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
struct rb_root *root)
{
struct rb_node *other; while ((!node || rb_is_black(node)) && node != root->rb_node)
{
if (parent->rb_left == node)
{
other = parent->rb_right;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_left(parent, root);
other = parent->rb_right;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_right || rb_is_black(other->rb_right))
{
rb_set_black(other->rb_left);
rb_set_red(other);
__rb_rotate_right(other, root);
other = parent->rb_right;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->rb_right);
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
}
}
else
{
other = parent->rb_left;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_right(parent, root);
other = parent->rb_left;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_left || rb_is_black(other->rb_left))
{
rb_set_black(other->rb_right);
rb_set_red(other);
__rb_rotate_left(other, root);
other = parent->rb_left;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->rb_left);
__rb_rotate_right(parent, root);
node = root->rb_node;
break;
}
}
}
if (node)
rb_set_black(node);
} void rb_erase(struct rb_node *node, struct rb_root *root)
{
struct rb_node *child, *parent;
int color; if (!node->rb_left)
child = node->rb_right;
else if (!node->rb_right)
child = node->rb_left;
else
{
struct rb_node *old = node, *left; node = node->rb_right;
while ((left = node->rb_left) != NULL)
node = left; if (rb_parent(old)) {
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node;
else
rb_parent(old)->rb_right = node;
} else
root->rb_node = node; child = node->rb_right;
parent = rb_parent(node);
color = rb_color(node); if (parent == old) {
parent = node;
} else {
if (child)
rb_set_parent(child, parent);
parent->rb_left = child; node->rb_right = old->rb_right;
rb_set_parent(old->rb_right, node);
} node->rb_parent_color = old->rb_parent_color;
node->rb_left = old->rb_left;
rb_set_parent(old->rb_left, node); goto color;
} parent = rb_parent(node);
color = rb_color(node); if (child)
rb_set_parent(child, parent);
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child; color:
if (color == RB_BLACK)
__rb_erase_color(child, parent, root);
} static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data)
{
struct rb_node *parent; up:
func(node, data);
parent = rb_parent(node);
if (!parent)
return; if (node == parent->rb_left && parent->rb_right)
func(parent->rb_right, data);
else if (parent->rb_left)
func(parent->rb_left, data); node = parent;
goto up;
} /*
* after inserting @node into the tree, update the tree to account for
* both the new entry and any damage done by rebalance
*/
void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data)
{
if (node->rb_left)
node = node->rb_left;
else if (node->rb_right)
node = node->rb_right; rb_augment_path(node, func, data);
} /*
* before removing the node, find the deepest node on the rebalance path
* that will still be there after @node gets removed
*/
struct rb_node *rb_augment_erase_begin(struct rb_node *node)
{
struct rb_node *deepest; if (!node->rb_right && !node->rb_left)
deepest = rb_parent(node);
else if (!node->rb_right)
deepest = node->rb_left;
else if (!node->rb_left)
deepest = node->rb_right;
else {
deepest = rb_next(node);
if (deepest->rb_right)
deepest = deepest->rb_right;
else if (rb_parent(deepest) != node)
deepest = rb_parent(deepest);
} return deepest;
} /*
* after removal, update the tree to account for the removed entry
* and any rebalance damage.
*/
void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data)
{
if (node)
rb_augment_path(node, func, data);
} /*
* This function returns the first node (in sort order) of the tree.
*/
struct rb_node *rb_first(const struct rb_root *root)
{
struct rb_node *n; n = root->rb_node;
if (!n)
return NULL;
while (n->rb_left)
n = n->rb_left;
return n;
} struct rb_node *rb_last(const struct rb_root *root)
{
struct rb_node *n; n = root->rb_node;
if (!n)
return NULL;
while (n->rb_right)
n = n->rb_right;
return n;
} struct rb_node *rb_next(const struct rb_node *node)
{
struct rb_node *parent; if (rb_parent(node) == node)
return NULL; /* If we have a right-hand child, go down and then left as far
as we can. */
if (node->rb_right) {
node = node->rb_right;
while (node->rb_left)
node=node->rb_left;
return (struct rb_node *)node;
} /* No right-hand children. Everything down and left is
smaller than us, so any 'next' node must be in the general
direction of our parent. Go up the tree; any time the
ancestor is a right-hand child of its parent, keep going
up. First time it's a left-hand child of its parent, said
parent is our 'next' node. */
while ((parent = rb_parent(node)) && node == parent->rb_right)
node = parent; return parent;
} struct rb_node *rb_prev(const struct rb_node *node)
{
struct rb_node *parent; if (rb_parent(node) == node)
return NULL; /* If we have a left-hand child, go down and then right as far
as we can. */
if (node->rb_left) {
node = node->rb_left;
while (node->rb_right)
node=node->rb_right;
return (struct rb_node *)node;
} /* No left-hand children. Go up till we find an ancestor which
is a right-hand child of its parent */
while ((parent = rb_parent(node)) && node == parent->rb_left)
node = parent; return parent;
} void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root)
{
struct rb_node *parent = rb_parent(victim); /* Set the surrounding nodes to point to the replacement */
if (parent) {
if (victim == parent->rb_left)
parent->rb_left = new;
else
parent->rb_right = new;
} else {
root->rb_node = new;
}
if (victim->rb_left)
rb_set_parent(victim->rb_left, new);
if (victim->rb_right)
rb_set_parent(victim->rb_right, new); /* Copy the pointers/colour from the victim to the replacement */
*new = *victim;
}
红黑树的测试文件(test.c)
/**
* 根据Linux Kernel定义的红黑树(Red Black Tree)
*
* @author skywang
* @date 2013/11/18
*/ #include <stdio.h>
#include <stdlib.h>
#include "rbtree.h" #define CHECK_INSERT 0 // "插入"动作的检测开关(0,关闭;1,打开)
#define CHECK_DELETE 0 // "删除"动作的检测开关(0,关闭;1,打开)
#define LENGTH(a) ( (sizeof(a)) / (sizeof(a[0])) ) typedef int Type; struct my_node {
struct rb_node rb_node; // 红黑树节点
Type key; // 键值
// ... 用户自定义的数据
}; /*
* 查找"红黑树"中键值为key的节点。没找到的话,返回NULL。
*/
struct my_node *my_search(struct rb_root *root, Type key)
{
struct rb_node *rbnode = root->rb_node; while (rbnode!=NULL)
{
struct my_node *mynode = container_of(rbnode, struct my_node, rb_node); if (key < mynode->key)
rbnode = rbnode->rb_left;
else if (key > mynode->key)
rbnode = rbnode->rb_right;
else
return mynode;
} return NULL;
} /*
* 将key插入到红黑树中。插入成功,返回0;失败返回-1。
*/
int my_insert(struct rb_root *root, Type key)
{
struct my_node *mynode; // 新建结点
struct rb_node **tmp = &(root->rb_node), *parent = NULL; /* Figure out where to put new node */
while (*tmp)
{
struct my_node *my = container_of(*tmp, struct my_node, rb_node); parent = *tmp;
if (key < my->key)
tmp = &((*tmp)->rb_left);
else if (key > my->key)
tmp = &((*tmp)->rb_right);
else
return -;
} // 如果新建结点失败,则返回。
if ((mynode=malloc(sizeof(struct my_node))) == NULL)
return -;
mynode->key = key; /* Add new node and rebalance tree. */
rb_link_node(&mynode->rb_node, parent, tmp);
rb_insert_color(&mynode->rb_node, root); return ;
} /*
* 删除键值为key的结点
*/
void my_delete(struct rb_root *root, Type key)
{
struct my_node *mynode; // 在红黑树中查找key对应的节点mynode
if ((mynode = my_search(root, key)) == NULL)
return ; // 从红黑树中删除节点mynode
rb_erase(&mynode->rb_node, root);
free(mynode);
} /*
* 打印"红黑树"
*/
static void print_rbtree(struct rb_node *tree, Type key, int direction)
{
if(tree != NULL)
{
if(direction==) // tree是根节点
printf("%2d(B) is root\n", key);
else // tree是分支节点
printf("%2d(%s) is %2d's %6s child\n", key, rb_is_black(tree)?"B":"R", key, direction==?"right" : "left"); if (tree->rb_left)
print_rbtree(tree->rb_left, rb_entry(tree->rb_left, struct my_node, rb_node)->key, -);
if (tree->rb_right)
print_rbtree(tree->rb_right,rb_entry(tree->rb_right, struct my_node, rb_node)->key, );
}
} void my_print(struct rb_root *root)
{
if (root!=NULL && root->rb_node!=NULL)
print_rbtree(root->rb_node, rb_entry(root->rb_node, struct my_node, rb_node)->key, );
} void main()
{
int a[] = {, , , , , , , , };
int i, ilen=LENGTH(a);
struct rb_root mytree = RB_ROOT; printf("== 原始数据: ");
for(i=; i<ilen; i++)
printf("%d ", a[i]);
printf("\n"); for (i=; i < ilen; i++)
{
my_insert(&mytree, a[i]);
#if CHECK_INSERT
printf("== 添加节点: %d\n", a[i]);
printf("== 树的详细信息: \n");
my_print(&mytree);
printf("\n");
#endif } #if CHECK_DELETE
for (i=; i<ilen; i++) {
my_delete(&mytree, a[i]); printf("== 删除节点: %d\n", a[i]);
printf("== 树的详细信息: \n");
my_print(&mytree);
printf("\n");
}
#endif
}
rbtree.h和rbtree.c基本上是从Linux 3.0的Kernel中移植出来的。仅仅只添加了offestof和container_of两个宏,这两个宏在文章"Linux内核中双向链表的经典实现"中已经介绍过了,这里就不再重复说明了。
test.c中包含了两部分内容:一是,基于内核红黑树接口,自定义的一个结构体,并提供了相应的接口(添加、删除、搜索、打印)。二是,包含了相应的测试程序。
红黑树(三)之 Linux内核中红黑树的经典实现的更多相关文章
- 作业三:LINUX内核的启动过程
作业三:LINUX内核的启动过程 一.使用GDB跟踪内核从start_kernel到init进程启动(附实验截图) (一)使用自己的Linux系统环境搭建MenuOS的过程 下载内核源代码编译内核 c ...
- Linux内核中双向链表的经典实现
概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核 ...
- Linux内核及分析 第三周 Linux内核的启动过程
实验过程: 打开shell终端,执行以下命令: cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage-initrd rootf ...
- 详解Linux内核红黑树算法的实现
转自:https://blog.csdn.net/npy_lp/article/details/7420689 内核源码:linux-2.6.38.8.tar.bz2 关于二叉查找树的概念请参考博文& ...
- C高级 框架开发中红黑树结构
引言 -- 红黑树历史 红黑树是数据结构学习中一道卡. 底层库容器中必不可少的算法. 历经各种实战运用,性能有保障. 同样红黑树不好理解, 就算理解了, 代码也不好写. 就算写了, 工程库也难构建. ...
- linux 内核数据结构之红黑树.
转载: http://www.cnblogs.com/haippy/archive/2012/09/02/2668099.html https://zh.wikipedia.org/zh/%E7%BA ...
- 《Linux内核分析》课程第三周学习总结
姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- linux内核分析 第三周 构造一个简单的Linux系统MenuOS
一.计算机的三个法宝 存储程序计算机,函数调用堆栈,中断二.操作系统的两把剑:1.中断上下文的切换,保存现场和恢复现场2.进程上下文的切换. 三.linux内核源代码的分析: ·arch/目录保存支持 ...
- Linux内核分析(三)内核启动过程分析——构造一个简单的Linux系统
一.系统的启动(各历史节点) 在最开始的时候,计算机的启动实际上依靠一段二进制码,可以这么理解,他并不是一个真正的计算机启动一道程序.计算机在开始加电的时候几乎是没有任何用处的,因为RAM芯片中包括的 ...
随机推荐
- Extjs4中RadioGroup的赋值与取值
1.定义rg var rg = new Ext.form.RadioGroup({ fieldLabel : "test", items : [{ boxLabel : '每天', ...
- android: SharedPreferences实现记住密码功能
既然是实现记住密码的功能,那么我们就不需要从头去写了,因为在上一章中的最佳实 践部分已经编写过一个登录界面了,有可以重用的代码为什么不用呢?那就首先打开 BroadcastBestPractice 项 ...
- 【VerySky原创】 ME9F
[VerySky原创] V_EKKONA - Generierte Tabelle zu einem View V_EKKONA-PFLD4 字段 SE71查看 至于图片:在表STXBITMAPS中 ...
- ArrayList/Vector的原理、线程安全和迭代Fail-Fast
疑问 * ArrayList是非线程非安全的,具体是指什么?具体会产生什么问题?* ArrayList的内部原理是什么?为什么可以动态扩容?* Vector是线程安全的,具体是如何实现的?为什么不再推 ...
- ClamAV安装使用及API例子
ClamAV是一款由Sourcefire组织开发的开源杀毒引擎,Sourcefire同时也是Snort入侵检测引擎的所有者.ClamAV提供了一种更为快速灵活的框架用以检测恶意代码和软件产品.可以作为 ...
- iOS 日志
去掉日志 #ifndef __OPTIMIZE__ #define NSLog(...) NSLog(__VA_ARGS__) #else #define NSLog(...){} #endif 打开 ...
- burp suite 使用教程详解(外文翻译转)
Burp Suite是Web应用程序测试的最佳工具之一,其多种功能可以帮我们执行各种任务.请求的拦截和修改,扫描web应用程序漏洞,以暴力破解登陆表单,执行会话令牌等多种的随机性检查.本文将做一个Bu ...
- android 6.0权限判断 音频 拍照 相册
------------------------------------------打开音频权限------------------------------------------------ if ...
- VC++ 学习笔记(序):神一样的语言
总的来说,我觉得VC++是一门神一样的语言——它是公认最强大.最复杂的:它一切以效率为第一要务,却又不肯落伍,拼命兼容现在的新的语言设计特点.本来在别的语言很容与就避开的问题,在这里要用很高的技巧去设 ...
- 301 redirect Domain Name using global.asax
void Application_BeginRequest(object sender, EventArgs e) { if (HttpContext.Current.Request.Url.ToSt ...