kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

通过绝对内存地址进行参数赋值与函数调用

同一个数可以通过不同的方式表达出来,对于函数的访问,变量的赋值除了直接对变量赋值以外,还可以通过绝对内存地址进行参数赋值与函数调用。

1、通过地址修改变量的值

1
2
3
4
5
6
int x;
int *p;
printf("%x\n",&x);
p=(int *)0x0012ff60;
*p = 3;
printf("%d\n",x);

程序的输出结果为:
12ff603

程序首先输出变量x所在地址为十六进制的0x12ff60(本来应该为8位的十六进制数,高位为0则省略掉),然后定义一个指针变量,让它指向该地址,通过指针变量的值来修改变量x的值。

示例代码:

1
2
3
int *ptr=(int*)0xa4000000;
*ptr=0xaabb;
printf("%d\n",*ptr);

以上程序会崩溃,因为这样做会给一个指针分配一个随意的地址,很危险,所以这种做法是不允许的。

2、通过地址调用函数的执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>using namespace std; 
typedef void(*FuncPtr)() ;
 
void  p()
{ 
	printf("MOP\n");
}   
 
int main()
{
	void (*ptr)();
	p();
	printf("%x\n",p);
	ptr = (void (*)())0x4110f0;
	ptr();//函数指针执行
	((void (*)())0x4110f0)();
	((FuncPtr)0x4110f0)();
	return 0;
}

程序执行结果如下:
MOP4110f0MOP
MOP
MOP

首先定义一个ptr的函数指针,第一次通过函数名调用函数,输出Mop,打印函数的入口地址,函数的入口地址为4110f0。然后给函数指针ptr赋地址值为p的入口地址,调用ptr,输出Mop。接着的过程是不通过函数指针直接执行,仍然使用p的入口地址调用,输出为MOP。最后是通过typedef调用的直接执行。

函数名称、代码都是放在代码段的,因为是放在代码段,每次会跳到相同的地方,但参数会压栈,所以函数只根据函数名来获取入口地址,与参数和返回值无关。无论参数和返回值如何不同,函数入口地址都是一个地方。

对以下程序进行分析如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h> int   p(int a,int b) 
{ 
	return 3;
}   
 
int main()
{
	printf("%x\n",p);
	int a = p(2,3);
	printf("%d\n",p);
	int b = p(4,5);
	printf("%x\n",p);
	return 0;
}

程序输出结果如下:
4111594264281411159
十六进制的411159转换成十进制的值为4264281。程序中打印的p的入口地址,无论p是否调用函数,入口地址都没有改变。 分析如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h> int  p(int a,int b) 
{ 
	return ((a>b)?a:b);
}  
int main()
{
	int (*ptr)(int ,int);
	ptr = (int (*)(int,int))0x411159;
	int c = ptr(5,6);
	printf("%d\n",c);
	return 0;
}

程序输出为:
6 通过函数指针调用有返回值和参数的函数,不适用函数名,而是用函数入口地址调用。
函数存放在内存的代码区域内,也有地址,一个函数在编译时被分配一个入口地址,将这个入口地址称为函数的指针,函数的地址就是函数的名字。 函数指针不能指向不同类型或是带不同形参的函数。

ubuntu(>=12.04) N卡双显卡 切换

http://blog.sina.com.cn/s/blog_6dee445401013sss.html
http://www.cnblogs.com/congbo/archive/2012/09/12/2682105.html
http://wenku.baidu.com/view/e69d3019650e52ea551898e0.html

NVIDIA的Optimus技术可让笔记本根据性能需要在英特尔集成显卡和NVIDIA独显之间自动切换,节省电力。 但这项技术不支持Linux。现在,NVIDIA工程师透露他们正致力于实现Linux支持。 NVIDIA的Aaron Plattner在邮件列表上说,他已经在新的Linux版驱动上概念验证了Optimus,未来Linux笔记本用户有望获得Optimus支持。

当你美滋滋的装好了ubuntu之后,习惯性的用自带的驱动检测工具给装上显卡驱动,以为大功告成的时候,肯跌的事情来了,当你重启你会发现,黑 屏!!!!!!!!!!!木有错,你进不去X桌面了,这就是双显卡的悲剧,咋办捏?就这样放弃么,肿么可能,用linux就必修经得起折腾,于是上网狂找 资料,发现一个第三方的玩意貌似可以解决,叫Bumblebee(大黄蜂) ,Nvidia的双显卡切换叫Optimus(擎天柱),还有一个双显卡切换的软件ironhide(铁皮)。大黄蜂是唯一完美解决的

第一步:安装我们的主角Bumblebee(大黄蜂)

1
2
3
4
5
6
sudo add-apt-repository ppa:bumblebee/stable
sudo apt-get update
sudo apt-get install bumblebee bumblebee-nvidia
// 12.04.2 安装时出现需要:nvidia-current  但依赖:XXX 的情况不要安装nvidia-current,
// 而是添加源:sudo add-apt-repository ppa:ubuntu-x-swat/x-updates,然后再执行 sudo apt-get install bumblebee bumblebee-nvidia
sudo reboot

ps: Bumblebee3 已经非常完善,把所有的东西都配置好了

第二步:查看显卡工作状态

1
2
3
4
lspci |grep VGA
结果如下:
00:02.0 VGA compatible controller: Intel Corporation 2nd Generation Core Processor Family Integrated Graphics Controller (rev 09)
01:00.0 VGA compatible controller: NVIDIA Corporation GF108 [GeForce GT 540M] (rev ff)

独显的状态为rev ff 即为关闭状态,OK 大功告成!


下面非必需,也许要装拓展才能运行下面的命令

打开N卡设置
optirun nvidia-settings -c :8

下边两个命令可以对比开独显跟不开独显的性能差距
glxgears // 直接运行

optirun glxgears //使用独显运行
Ps:optirun XXX 就是调用独显的关键了,这个就是指明用独立显卡打开指定的xxx程序

  • 可以自己先装高版本nvidia,再装bumblebee,这样似乎性能更好?

  1. bumblebee并不是单纯为了省电,是为了能初步使用双显卡所特有的optimus功能(说白了就是平时显示任务重的时候用独显渲染,普通显示用集显渲染),而鉴于nvidia官方驱动目前无法支持linux下双显卡模式,只能用bumblebee替代。(最新版本nvidia官方驱动初步支持双显卡模式,但是支持的很差,而且需要xrandr1.4+版本,强烈不建议使用)

  2. Nvidia的双显卡电脑是无法禁用集显而单独工作的,因为就算使用独显渲染,也必须依靠集显来显示输出。(可以简单理解为独显是通过集显间接连接在主板上)。

  3. 默认安装的系统是不带nvidia独显驱动的,所以默认驱动并正常工作的是集成intel显卡,而不是独显。在这种情况下,独显通电,发热,但是完全不起作用。但是你再装上nvidia的独显,由于目前linux下官方驱动并不支持双显卡的工作模式,所以结果一定是黑屏。。。

  4. 基于以上三点,bumblebee腾空出世。它本身并不是驱动,你可以看做是一个显卡驱动管理程序。安装好bumblebee之后,再安装bumblebee-nvidia来安装上官方驱动(你也可以自己下载安装nvidia官方驱动,或者nouveau开源驱动,但是不推荐,新手很容易出问题),这时候,你电脑上就有了intel的集显驱动和nvidia独显的官方驱动。bumblebee依赖与bbswitch(不用管他,会自动装上),会在系统运行时候,默认关闭掉独显,只使用集显(减少耗电和发热)。它并不会像windows下nvidia官方驱动那样提供智能的optimus功能,根据系统运行程序显示负担来判断是否需要独显工作。所以,如果你明确某个程序需要nvidia独显来渲染图形的时候,需要在terminal中手动输入optirun xxx来启动该程序。比如,你想用独显来显示网页,或者flash,可以用optirun firefox 命令来启动firefox, 而普通的firefox命令只会使用集显显示。

  5. 如果你想用独显玩dota2, 那么你需要用optirun steam来启动steam客户端,然后再启动游戏,这样游戏就是通过独显来渲染的。你也可以用普通的steam命令来启动steam,然后在dota2游戏的属性中,加入启动方式optirun %command。 这样只有在启动游戏之后独显才会工作。

  6. 如果安装完成bumblebee或者nvidia驱动之后,系统启动出现黑屏,解决方法很简单,ctl+alt+ 1或2或。。。。6,都可以,进入模拟终端,输入用户名和密码,删除掉/etc/X11/xorg.conf文件,再重启一定能启动图形界面。


今天下完了13.04,惯例安装显卡驱动,报错

c/c++函数扩展名

  • 后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序;
  • 后缀为.cpp的,两者都会认为是c++程序
1
2
3
4
5
6
int printf(char*, ...);
int main()
{
	printf("test\n");
	return 0;
}
一、

保存为.c 文件, 用gcc编译能通过,g++编译不能通过。
g++会判定是不是你自己声明的函数,如果是,它会按照一种规则去重命名该函数。c++为了支持重载才这么做,而c没有重载。

二、

保存为.cpp文件,用gcc、g++都编译不能通过

上下文无关文法

上下文无关文法有足够的能力描述现今程序设计语言的语法结构,比如描述算术表达式,描述各种语句等。

1.上下文无关文法语法树

给定文法G=(VN,VT,P,S),对于G的任何句型都能构造与之关联的语法树(推导树)。这棵树满足下列4个条件:
① 每个结点都有一个标记,此标记是V的 一个符号。
② 根的标记是S。
③ 若一结点标记A,至少有一个从它出发的分枝,则A肯定在VN中
④ 如果标记为A,有n个从它出发的分枝,并且这些分枝的结点的标记(从左到右)为B1, B2,…,Bn,那么A→B1B2,…,Bn一定是P中的一个产生式。
例:

1
2
3
4
5
6
G[S]:
S→aAS
A→SbA
A→SS
S→a
A→ba

写出aabbaa句型的推导过程:

1
2
(1)S=>aAS=>aAa=>aSbAa=>aSbbaa=>aabbaa(最右推导)
(2)S=>aAS=>aSbAS=>aabAS=>aabbaS=>aabbaa(最左推导)

2.句型、推导

1
2
3
G[E]: E→E+T|T
T→T*F|F
F→(E)|a

判断a+a*a是否是合法的句子,采用最左推导和最右推导

1
2
E=>E+T=>T+T=>F+T=>a+T=>a+T*F=>a+F*F=>a+a*F=>a+a*a(最左推导)
E=>E+T=>E+T*F=>E+T*a=>E+F*a =>E+a*a=>T+a*a=>F+a*a=>a+a*a(最右推导)

3.规范推导、规范句型

最左(最右)推导:在推导的任何一步αTβ,其中α、β是句型,都是对α中的最左(右)非终结符进行替换。最右推导被称为规范推导。

由规范推导所得的句型称为规范句型。任何句子都有规范推导,但句型不一定有规范推导。
例:设语言L1={n|n是无符号整数}且文法G: N =>ND N =>D
D =>0|1|2|3|……|9
对于该文法,3D是句型,但不存在规范句型。
而33是存在规范句型。
N=>ND=>DD=>3D (不是最右推导)
N=>ND=>N3=>D3=>33 (是最右推导)

4.构造语法树

1
2
3
4
G[E]:
E→E+T|T
T→T*F|F
F→(E)|a

画出a+a*a句型的语法树

一棵语法树表示了一个句型的可能的不同推导过程,包括最左(最右)推导。但是,一个句型是否只对应唯一的一棵语法树呢?一个句型是否只有唯一的一个最左(最右)推导呢?
例:

1
2
3
4
5
G[E]
E->i
E->E+E
E->E*E
E->(E)

句型i*i+i两个不同的最左推导

1
2
E=>E+E=>E*E+E=>i*E+E=>i*i+E=>i*i+i
E=>E*E=>i*E=>i*E+E=>i*i+E=>i*i+i

5.二义文法

若一个文法存在某个句子对应两棵不同的语法树,则称这个文法是二义的或者,若一个文法存在某个句子有两个不同的最左(右)推导,则称这个文法是二义的。
对于一个程序设计语言来说,常常希望它的文法是无二义的,因为希望对它的每个语句的分析是唯一的。
二义文法改造为无二义文法

1
2
3
4
G[E]:    E → i             G[E]: E → T|E+T
      E → E+E                       T → F|T*F
      E → E*E                       F → (E)|i
      E → (E)               规定优先顺序和结合律 

ssh利用RSA公钥远程登录验证

1、本地机器生成密钥
1
$ssh-keygen -t rsa

生成基于ssh协议第二版密钥,如果还是用rsa1,该升级了。

2、复制生成的id_rsa.pub公钥文件到远程服务器,简单的用:
1
$scp id_rsa.pub bsduser@192.168.1.188:mykey.pub
3、密码登陆远程服务器:
1
$ssh 192.168.1.188 -l bsduser

这里注意不是cp,而是cat;不是">“,而是”>>“的操作:

1
%cat mykey.pub >> $HOME/.ssh/authorized_keys
4、重启sshd
1
#/etc/rc.d/sshd restart
5、此时进行登录测试:
1
$ssh bsduser@192.168.1.188

成功,则可以不用输入繁琐和易泄露的密码。但是条件是你要保护好自己的密钥文件信息。

  • 注意authorized_keys文件权限设置600

  • 服务器上若对用户主目录进行了软链接,则软链接的目录权限要小等于755。如 ln -s /opt/kk /home/kk, 则需要chmod 755 /opt/kk,不然会不起作用。