Anders Hejlsberg解析现代compiler

Anders Hejlsberg on modern compiler architecture

Anders大神曾是TurboPascal作者以及Delphi的首席架构师,后来在微软负责Visual J++和MFC的架构。再后来成为C#和.NET的主要设计师和Typescript的核心贡献者。这个视频是他在channel9对现代编译器的一个white board talker。我只略懂一些编译原理的知识。总结下:现代的编译器基于language server, 修改即解析,复用sytax tree。多了很多Json的消息交互,对机器的性能要求更高。

ROS的序列化设计

    正好汇报下这个问题,这篇文章主要讲ROS如何做消息的序列化设计:

1, ROS如何做消息的多类型适配。

2, C++的模板和智能指针在ROS消息模块的应用。

3, 如何通过去除序列化和反序列化来增强ROS的实时性。

 

消息的多类型适配

ROS提供基本类型( uint8_t, uint16_t, uint32_t, double ,float)外,还提供duration,Time等自定义的定长类型。此外Header,String,Arrary这种变长类型的消息。

为什么需要typename因为在引用时,编译器需要知道 这样写class::typename 到底是嵌套类型,还是静态函数或成员变量。Serializer<T>::write/read接口的设计把模板的能力发挥的恰到好处。

邪恶的proxy

    在具有成熟规模的公司里,Proxy配置的颇为艰难。注意,我在这里说的是带用户名和密码的proxy,而不是默认proxy。 大多数应用程序的Use system proxy settings选项在这种场景下形同虚设。。

你以为你export了全局proxy变量就没事了。

结果应用A跳出来不能访问网络,因为不能使用系统proxy,你只好在应用里配置好proxy。以此类推应用B, 应用C。

你以为使用cnNTLM之类的软件在windows上把代理配置127.0.0.1:8080就没事了。。。不。。proxy不允许你这么干了。。。两边协议版本一升级可能用户自己都不知道发生了什么,也不想去折腾。。。

我的工作环境是win7+ubuntu,那apt,clion,android studio甚至firefox等等。。一一要照顾到它的proxy配置。

比如添加一个key:sudo apt-key adv –keyserver-options http-proxy=http://USER:PASSWORD@PROXY_URL:PORT/ –keyserver keyserver.ubuntu.com –recv-keys GPG_KEY

比如apt的proxy竟然要单独的创建: acquire::http::proxy “http://USER::PASSWARD#PROXY_URL:PORT”

比如android studio需要在gradle里配置proxy参数…..

不管到哪都带着一个叫做proxy的恶魔参数。。。

好歹今天你学习到一点: Sudo -E xxxx-command. 把系统环境变量带入命令行,期望大多数工具能够自己读取系统proxy吧。

只是期望。邪恶仍将无处不在。

密码保护:note-private

这是一篇受密码保护的文章,您需要提供访问密码:

远程桌面

即使是多年经验的工程师也需要尴尬的承认,配置软件环境比想象的需要多一些时间(特别是不常用的工具)

VNC

1, 使用RealVNC,TigerVNC之类的软件远程桌面。我较强的诉求是调整桌面大小。通常这类软件提供一些图像显示的depth和size设置。比如RealVNC会推荐:

vncserver-virtual :1 -depth 24 -geometry 1440×900

:1 是桌面的虚拟显示器ID。登录时端口为:5900+该ID

depth: 图像显示深度

geometry: 桌面的显示大小

按照realvnc官网这篇文章介绍,你通常并不能顺利的设置桌面大小。我的环境是Ubuntu 16.04 Server(gnome,lxde,xfce)。 因为一些不知道的原因,导致这条命令配置完,使用realvnc的客户端登录上去时显示为灰色不可用的桌面。偶尔有几次却又是正常的。不得不反复去查log。

所以,退而求其次的使用

systemctl start vncserver-x11-serviced

但这种只能使用默认大小。

update: 使用tigerVNC的最新版本,根本不用考虑太多。而且还很方便。其自带的java客户端简单且方便使用。

1,安装tigerVNC的deb包。

2,vncserver :1 -depth 24 -geometry 1380×900 (随意设置大小)

3, 如果使用的是Ubuntu,那么很有可能一进去是没有侧边栏之类显示的。原因是~/.vnc/xstartup的脚本确实需要仔细调试。经过一番测试,使用以下配置没有问题,并且可以使用上unity。

xrdb $HOME/.Xresources
xsetroot -solid grey
x-window-manager &
unity &

其余脚本统统多余。。

X11-Forwarding

如果没有对桌面有很强烈的美感需求,使用x11-forwarding真的是一个很好的选择。

1,配置/etc/ssh/sshd_config下的

X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes

2,使能Putty的 Connection/SSH/X11/Enable X11 forwarding。

3,在X display location填上:localhost:10(sshd_config里的默认偏移号)。

4, 使用xming或者mobaXterm直接输入带GUI程序的二进制。

使用x11-forwarding过程中发现,除了Visual Studio Code的菜单显示有问题外。其它的GUI程序基本正常,甚至Android Studio的调试模拟器也能很好的显示出来。我认为基本能够满足日常需要。

总结:

1, 对x11的启动脚本要有一些认识,要了解xstartup每行脚本的具体作用。

2,realvnc的老版本不要使用,非常不方便。可能收费版本会好些。(我用的是一个老的有license的版本)。

3,客户端是通用的,用realvnc的客户端也可以访问tigervnc的server。因为遵循一样的通信协议(Virtual Network Computing)。

4,网上的一些声音:xfce桌面会快一些,容易配置一些。

5,x11-forwarding基本够用。颜值党上vnc。

xamarin的一点调研

跨平台开发一直很fancy。实际情况是有经验的开发者通常能够猜到他们需要付出的代价。

xamarin声称自己能够复用几乎所有的代码。这意味着ios上写的代码逻辑可以复用到android和windows phone上,听起来有点不可思议。怎么做到的呢?

答案就是提供调用本地库, 第三方库的能力。

1,但xamarin要适配最新的os,一定要会比native开发更慢,它提供的sdk要去适配新的native api。

2,而且中间肯定有适配层,如果一个跨平台的小白直接使用这种能力,就意味着做出来的应用效率更差。

3,如果对性能有要求,就必须同时设计开发两个平台的应用程序。考虑到复用逻辑的效率,库的使用是否满足跨平台的要求。

4,如果只是有一个android程序,想迁移到ios版本,重新使用xamarin封装。那基本就是从头再写。从网上的反应看来,代价不少。

综上所述:使用visual studio for mac 开发跨平台的应用,更适合那些已经熟练使用C#的开发者。让这些开发者快速搭建原型,享受一次开发多平台部署的快感。毕竟这种感觉,目前只有xamarin才能带给你。

c++的{}和()

{} 提供列表初始化的功能,最终调用的是构造函数。比如

Point{ }

调用的是Point::Point()构造函数。而

Point{x,y}

调用的是Point::Point(x,y)构造函数。

所以,{ } 以初始化列表的方式explicit的调用了构造函数。提供了除了New,Operator New, placement New以外的创造新类的方法。

构造出一个匿名的类直接使用 Point{}即可,它调用构造函数,但是临时的,没有名字来指向它。所以调用完再也无法找到这个匿名类。

Point{}; // 调用构造,收工。

通常情况下我们使用有名字的类 ,这样后面的代码可以引用:

Point a{}; // a这个类可以在后面用。

为了使用类的这种匿名功能,通常标准库会这样玩,比如<utility>头文件中的std::hash就可以这样使用:

std::hash<std::string>{}(“/sensor/percept/lidar_topic”);

它得到一个size_t的hash字符串。

TLS协议和HTTP的嵌套

抓了一个TLSv1.2的协议包

协议可以互相嵌套

— ethernet II (SA,DA)

— Internet Protocol(SIP,DIP)

— Transmission Control Protocol( sport,dport,seq,ack,len)

— Hypertext Transfer Protocol( Proxy 443)

— Secure Socket Layer(Application Data Protocol http2, encrypted app data)

— Hypertext Transfer Protocol

— Secure Socket Layer

mojave下c++ functional

如果在Mojave下工作,可以发现Mac的可选的编译器种类比较多:

简单来说,如果使用了brew+安装了xcode。至少有以下几个编译器:

1, gcc-5/g++-5 : 不支持functional

2, x86_64-apple-darwin14.3.0-g++6 / x86_64-apple-darwin14.3.0-gcc-6:正常使用。

3, clang++/clang: 版本10.0.1, 不支持std::bind

测试代码如下:

#include <iostream>
#include <functional>

/*---- c function pointer ------*/
typedef  int (*myfunc)(int a,int b);

int abc(int a, int b )
{
  std::cout<<"i am original fp: "<< a << " " << b<<std::endl;
  return 0;
}

/*----class function ------*/
class test{
public: 
   test(int mem):member(mem){};
    ~test(){};
  int m_func(int a, int b)
  {
     std::cout<<"member function:  " << a << "  " << b<<std::endl; return 0;
  };
 private:
    int member;
};


int main()
{
    // use class instance member to init a std::function
    test ins(2);
    std::function<int(int,int)> a = std::bind(&test::m_func,&ins,std::placeholders::_1,std::placeholders::_2);
    a(1,2);
    
    // use raw c function pointer to init a std::function
    std::function<int(int,int)> b(abc);
    b(3,3);

    // use a lamda expr. to init a std::function
    std::function<int(int,int)> c( [](int a, int b)->int{ std::cout<<"lamda oks"<<std::endl; return 0;} );
    c(4,4);

    /* amazing, you can get raw function point from std::function
      but this not recommended by ISO c++ */
    myfunc* d = b.target<myfunc>();
    (*d)(1,2);
    std::cout<< "function address:  " << d<<std::endl;
    std::cout<<b.target_type().name()<<"  ==vs=== " <<typeid(myfunc).name()<<std::endl;
   
    // but this will cause a segmentation fault !    
    myfunc* e = a.target<myfunc>();
    //(*e)(666,666);
    std::cout<< e<<std::endl;
    std::cout<<a.target_type().name()<<"  ==vs=== " <<typeid(myfunc).name()<<std::endl;
    
    // but this will cause a segmentation fault ! 
    myfunc* f = c.target<myfunc>();
    std::cout<< f<<std::endl;
    std::cout<<c.target_type().name()<<"  ==vs=== " <<typeid(myfunc).name()<<std::endl;
     
    //(*f)(999,999);
}

输出如下:

member function: 1 2
i am original fp: 3 3
lamda oks
i am original fp: 1 2
function address: 0x7b52c2300e80
PFiiiE ==vs=== PFiiiE
0
St5_BindIFSt7_Mem_fnIM4testFiiiEEPS1_St12_PlaceholderILi1EES6_ILi2EEEE ==vs=== PFiiiE
0
Z4mainEUliiE_ ==vs=== PFiiiE

总结:

1,std::function 友好的封装了函数指针,适用于函数回调的场景。

2,内部使用了多态,同时🈶很好的类型检查。如果在嵌入式场景下使用,引入的库带来的负担较重,需要仔细斟酌。

3,成员函数和Lambda表达式不能通过target获取指针,原因是不知道该函数类型。这意味着不能随意的把一个成员函数指针和Lamda变成一个C函数指针。这会给C++库赋值给C库的回调函数带来一定的使用限制。

4,静态函数和普通全局函数可以很方便的和std::function转换。

apollo-11的AGC

Twitter上Lin Clark骄傲的宣布自己老妈Magret Hamilton 50年前写的Apollo 11登月代码被人推上了GitHub库。

的确是一件让人骄傲的事情。我挖了下,Hamilton当时写的的显示接口部分。详细见: http://www.ibiblio.org/apollo/
但同时,她是AGC的Programming Leader。

也很感叹网上一堆人才们开发了AGC(Apollo Guidance Computer)的模拟器,https://github.com/virtualagc/virtualagc。
毕竟是人类第一次登月。第一次开发core rope这种原始的存储设备,第一次提出软件工程的概念,第一次利用我们现在看来原始的代码
帮助人类送到从未触及的月球。放在现在,我们很多技术人员还没有当年这拨程序员的水平。即使,我们有更先进的设备和技术。
Apollo-11是一个组织,一个政府,以及人类共同的集体合作结果。

以此纪念AGC提出的软件工程概念,在还没有C语言的年代:https://github.com/chrislgarry/Apollo-11