(转)谈谈写程序与学英语

注: 本文的作者是宋劲杉,原文链接。转载自网址

俗话说,没有金刚钻,就别揽瓷器活儿。套用到IT业,英语不行,就别做程序员。网上关于程序员学英语的文章不少,但我想谈谈我自己的看法。首先详细讨论一下为什么程序员离了英语不行,然后针对程序员应该怎么学英语说说我的体会。

英语是计算机的母语,是程序的母语,所以必然是程序员的母语。程序中的变量名、函数名起得好不好是决定代码质量和可维护性的最关键因素。高质量的代码应该是这样的:代码基本上是自解释的(self-explanatory),不需要太多注释,不管代码的规模有多大,具有相关知识背景的读过文档的人都可以立刻上手、立刻参与维护和开发。要想使代码能够自解释,给变量和函数起个好名字很关键,很显然,只能用英文起名字,一是用汉语拼音起名字可读性很差,二是英文单词通常比汉语更expressive(看吧,如果用汉语来说,就得说“表达能力更强”、“更有表现力”这么罗嗦),由于程序的复杂性,变量和函数往往表示一些很抽象的概念,起个既准确又简洁的名字并不容易,可是很多时候,用汉语需要很多字才能说清楚的一件事,用英文一个单词再加点词形变化就能说清楚了。例如APUE上讲sleep函数的实现,其中有个变量表示“本来应该睡到某个时刻,但是提前被信号唤醒了,唤醒时与本来应该睡到的时刻相差的时间”,如果为了简洁而不求准确,这个变量名至少也得叫“未睡到”,而书中只用了一个单词unslept,非常准确、简洁地表达了这个意思。为了写程序而学英语需要学到什么水平?我认为能起出这种变量名就够水平了。很多在IT外企工作的中国人,说话写文章经常夹杂着英文单词(比我严重多了因为我不在外企),非常可以理解,确实是为了表达得更准确简洁的需要,而不是纯为了play zhuangbility。总之,要写程序必须学好英语,否则连变量名都起不好,这虽然是一个非技术问题,但却是个根本问题,比任何技术问题都重要。当然,现在很多编程语言也支持用Unicode字符给变量和函数起名,但是你见过有人用汉字写程序吗?根本不实用。有人会辩驳说一页英文翻译成中文往往只占半页,中文不是更简洁吗?但是你算算打一页英文和打半页中文哪个敲键盘次数多。另外,要读别人的代码也必须学好英语,如果你不知道unslept是由 sleep变形而来的,就体会不到其中的精妙,只有大量阅读高质量的代码,才能写出高质量的代码,创作都是从模仿开始的。

Read More

C语言中宏定义存在位置

宏定义作为C语言的一个传统内容,如果使用新标准的话,一般也只用宏定义来结局编译的一些问题如:#ifndef,#if undefined()等。

宏定义究竟放在什么地方,在使用 C 语言老款编辑器情况下,一些程序大量使用宏定义,且很多程序都是将宏定义作为申明一样全部放在头文件中的,这个没有一个统一的说法,其中各有利弊,每个人风格不尽相同。

首先,宏定义的常量在编译的时候是作为内容直接替换的,因此这部分并不会因此占用你堆、栈等存储空间。所以这就导致无论你将宏定义放在头文件还是放在源文件中,资源消耗上面没有太大差别。差别就是在头文件和源文件中可以使用的作用域不同。

1. 放在头文件中:

  • 作用域更广,不仅仅对应源文件可以使用,且其他所有的源文件包含这个都可以使用,即便一些常量现在不会被使用,将来也可能会使用。
  • 作用域太宽,可能会与其他文件中的某个宏定义命名冲突,需要定义较长的名字。
  • 方便集中在一起进行管理,看起来代码更加显得整洁。

Read More

头文件交叉引用

尽可能将所需要包含的头文件文件在.c文件中包含定义如:#inlcude “x.h”,除非头文件必须的部分申明出现在其他头文件中定义过的结构体或者宏定义类型,这时候没办法,只能在.h中包含.h。

具体分析这样定义的原因:

1. 减少编译展开所需时间

虽然头文件中都加入了

1
2
3
4
#ifndef __KEY_H
#define __KEY_H
...
#endif

一般编译不会再出现重定等错误,但是每次遇到#include的时候,都会将这段代码复制一边进行排查,而头文件多次被展开,会严重影响编译效率,且也没有什么好处。

Read More

ubuntu的基本使用

本文专门针对ubuntu这个linux发行版而写的,对ubuntu特有一些操作进行介绍和总结。

dpkg

dpkg 是 Debian Packager 的简写,为 Debian 专门开发的套件管理系统,方便软件的安装、更新及移除。所有源自 Debian 的 Linux 发行版都使用 dpkg,例如 Ubuntu Knoppix 深度linux 等。

dpkg是用来安装.deb文件,但不会解决模块的依赖关系,且不会关心ubuntu的软件仓库内的软件,可以用于安装本地的deb文件。

  • 安装本地软件:dpkg -i <.deb file name>
  • 删除软件包(保留其配置信息):dpkg -r

其他一些详细操作这边就不罗列了,具体可查看 man 文件。

apt

apt会解决和安装模块的依赖问题,并会咨询软件仓库, 但不会安装本地的deb文件, apt是建立在dpkg之上的软件管理工具。

用过ubuntu的人都知道apt-get的方便

  • 远程安装软件:sudo apt-get install xxx ,远程库一般会提供不少常见的软件,当然也可以手动添加源。
  • 修复安装错误:sudo apt-get install -f 常用于手动安装软件后,出现错误,一般该指令可以解决大多数的依赖关系,一般这种错误来自于使用本地安装命令 dpkg 时出现的依赖错误。
  • 删除已经安装的软件:sudo apt-get remove xxx 删除一个软件包。

Read More

C编程规范

文章阐述了一些个人使用 C 编程时的习惯,主要参考一些网传的文档,固件库以及多个工程。

命名规则

结构体类型和函数的标识符一般用大驼峰式书写格式,普通变量和结构体变量的标识符则多用小驼峰式书写格式,但在此基础之上进行一定的改进不完全沿用。

宏定义的命名全部采用大写,单词之间用隔开,要求常量名只含有大写字母和下划线,且常量名用英文表达其意思不得使用拼音,当需要由多个单词表示时,单词与单词之间必须采用连字符”“连接。

1
2
如:
#define ERR_FILE_NOT_FOUND

全局变量、静态变量、常量尽可能的详细描述,普通局部变量和成员变量尽可能的书写简单;变量的描述都普遍按照小驼峰的方式。

这种命名法的出发点是把变量名按:属性+类型+对象描述的顺序组合起来:

Read More

常规的通讯校验

参考链接:
http://blog.csdn.net/liyuanbhu/article/details/7882789

Read More

GPIO口详解

在做 MCU 编程开发的时候,GPIO 可以说是最基础也是最重要的部分,MCU 的学习研究无非就是三点:高低电频,输入输出,通讯协议。而GPIO可以说贯穿始终,在模拟一些通讯协议时,GPIO 所采用的模式错误,往往会引起各种意想不到的问题。

对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的 IO 地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为 C 语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。比如像寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了,#define A (*(volatile unsigned long *)0x48000000) A = 0x01;这种通过宏定义某个存储空间,然后对该空间写入数据的过程是最为常见的。

GPIO 模式:

不同的 MCU 会提供不同的模式选择,一般 GPIO 的模式无外乎以下几种:推挽输出,开漏输出,浮空输入,上拉/下拉输入,模拟口,复用功能等等。

而实际使用中,

通用推挽输出(push-pull):

在功率放大器电路中大量采用推挽放大器电路,这种电路中用两只三极管构成一级放大器电路,两只三极管分别放大输入信号的正半周和负半周,即用一只三极管放大信号的正半周,用另一只三极管放大信号的负半周,两只三极管输出的半周信号在放大器负载上合并后得到一个完整周期的输出信号。原理图如下:

推挽放大器电路中,一只三极管工作在导通、放大状态时,另一只三极管处于截止状态,当输入信号变化到另一个半周后,原先导通、放大的三极管进入截止,而原先截止的三极管进入导通、放大状态,两只三极管在不断地交替导通放大和截止变化,所以称为推挽放大器

这种电路主要用于低功耗情况下能输出较大功率的交流信号,通常用于低频放大电路设计中。可增强输出的负载能力。这种输出结构带负载能力较强,你驱动个LED灯什么的操作IO口可以用推挽输出。

Read More

架设自己的git服务

本实验使用的是实体机 ubuntu 16.04 和虚拟机 virtualbox 搭建 ubuntu—server 16.04 系统进行连接,其中用 ubuntu-server 搭建 git,实体机 ubuntu desktop 连接 ubuntu-server,后续如果有其他环境也会逐一补充。

这边暂时没有在实体机上面尝试,先列举出在虚拟机上面架设 git 服务器

使用 ssh 登陆 ubuntu-server

ping 通两个系统:

看是否可以 ping 通两个系统,首先查看 ip 地址,ifconfig, 例如主机是: 192.168.18.60 ,虚拟机是 192.168.18.202。则在主机中 ping 192.168.18.60 ,当然事情往往并不会一帆风顺,很多设置的时候,为了可以链接外网,虚拟机选用了 NAT 模式。貌似该模式无法使用ssh服务,虚拟机可以 ping 通主机,但主机无法 ping 通虚拟机。这时候可以使用几种方法:

  • 更改虚拟机模式为桥接模式,弃用原来的 NAT 模式。
  • 使用实体机中的虚拟机网卡与虚拟机进行交互,但貌似 ubuntu 下面并无法找到这块虚拟网卡,解决办法可以手动建立一个虚拟网卡。
  • 创建一个新的链接方式,通过这个桥接到实体机,然后通过 NAT 访问外网。这边详细介绍这种方式

详细步骤:

  • 使用 virtualbox 新建一个新的 adapter,选用 bridge adapter。如下图:

  • 重启虚拟机系统,或者重启网络服务 sudo /etc/init.d/networking restart ,ifconfig -a 查看所有网卡,可以看到虚拟机中有一个网卡 enp0s8 并没有被使用,这个就是刚刚新建的那个桥接网卡。
  • 设置该网卡,修改/etc/network/interfaces文件,如下图:

  • 重启网络服务 sudo /etc/init.d/networking restart,ifconfig 查看网卡。如下图:
    -

  • 接着基本就可以尝试 ping 通两个系统了,实体机中使用 ping 192.168.18.202,虚拟机中 ping 192.168.18.60 。如果仍然不行可以尝试关闭防火墙:sudo ufw disable

Read More

多个发行版linux使用体验

本文主要记录自己使用多个linux的发行版的一些感受体验,会包括CLI和GUI的一些体验。本文具有一定的主观性,仅供参考。

发行版包括:ubuntu,debian,centOS,openSUSE等
窗口管理器包括:gnome,kde,awesome等

Read More

桥接、NAT、Host-only上网方式的区别

经常使用虚拟机的小伙伴们都遇到过网络链接过程中的各种问题,仔细查看设置会发现有:桥接、NAT、Host-only 等设置,vmware 等虚拟机后还会自动生成vmnet1和vmnet8,初学者可能会一头雾水,为啥只有两个?不是三种模式吗?另外每个模式代表什么?他们又有什么区别?无论是 vmware 还是 vitualbox 这些内容都大同小异,而 vmware 中看起来可能会更加直观些,这边以windows下的安装使用为例,进行深入的详解。

本文会尽可能详细地总结和罗列出三者的含义和区别,以及虚拟机中该如何配置他们更加合适。

桥接:

简而言之桥接就是指:就是通过一台设备(可能不止一个)把几个网络串起来形成的连接。这边主要介绍虚拟机所采用的桥接方式,虚拟出来的操作系统就像是局域网中的一独立的主机,它可以通过路由器网线访问网内任何一台机器。不过虚拟机需要占用你同一个网段的一个 IP 地址,当且仅当虚拟机和实体机在同一个网段,两者才可以进行通信,如:虚拟机 IP:192.168.1.101,实体机 IP:192.168.1.100

在桥接模式下,例如在 windows 下使用 vmware 时,明显看到会生成多个虚拟网卡出来,但却没有一个网卡是属于桥接的,原因是虚拟机采用桥接方式时,是不需要虚拟网卡的,这时候虚拟机操作系统和实体机操作系统同时使用真实网卡工作,然后真是网卡发送数据出去,而如果虚拟机发送数据给真实机,则数据流向是:虚拟机系统->真实网卡->路由器->真实网卡->实体机系统,不难看出同一个数据经过网卡在路由器上面绕了一圈又回到了网卡。

通过上述内容发现,桥接必须经过真实网卡和路由器,因此当你的电脑没有链接有线网或者无线网的话,你的实体机是无法和虚拟机进行交互的,即便看起来两者很近也不行。而选用桥接还是 NAT 等方式是在虚拟机软件中选定,进入虚拟的操作系统后,所有的设置和真实电脑没有本质区别,如果路由器允许自动分配 IP 地址,则操作系统设置为自动获取 IP 即可,如果不能自动分配,也可以在操作系统中手动分配 IP 地址。另外值得注意的是某些公司路由器绑定了电脑 mac 地址和 IP 地址,这时候虚拟机中的桥接也相当于一个真实电脑,也需要完成相关的绑定才可以访问网络。*

可以看出:如果你想利用VMware在局域网内新建一个虚拟服务器,为局域网用户提供网络服务,就应该选择桥接模式。下面举个栗子:

1
2
3
4
5
6
7
例如大学宿舍里有一个路由器,宿舍里四个人连接这个路由器,路由器的 wanip 就不理会了,这个 ip 是动态获取的,而一般lanip默认是192.168.1.1,子网掩码是255.255.255.0。而其他四个人是自动获取ip,假设四个人的 ip 是:
A: 192.168.1.100/255.255.255.0, B: 192.168.1.101/255.255.255.0, C: 192.168.1.102/255.255.255.0, D: 192.168.1.103/255.255.255.0
那么虚拟机的 ip 可以设置的 ip 地址是 192.168.1.2-192.168.1.99, 192.168.1.104-192.168.1.254 (网络地址 0 和 1 的除外,再除去 ABCD 四个人的 ip 地址)
那么虚拟机的 ip 地址可以设置为 192.168.1.98/255.255.255.0,设置了这个 ip 地址,ABCD 这四个人就可以通过 192.168.1.98 访问虚拟机了,如果虚拟机需要上外网,那么还需要配置虚拟机的路由地址,就是 192.168.1.1 了,这样,虚拟机就可以上外网了,但是,上网我们一般是通过域名去访问外网的,所以我们还需要为虚拟机配置一个 dns 服务器,我们可以简单点,把 dns 服务器地址配置为 google 的 dns 服务器 :8.8.8.8,到此,虚拟机就可以上网了。

综上所述,同一个数据经过网卡在路由器上面绕了一圈又回到了网卡。而虚拟机的桥接也只在其他电脑需要访问你电脑的虚拟机时,或者你虚拟机需要访问其他外部设备时才有相关需求*,一般情况还是建议配置成操作方便使用简单的 NAT 方式。

Read More