openwrt 工具链及 SDK 编译

主要步骤:
1. 下载源码
2. 更新 feeds
3. 配置编译项
4. 编译

主要参考:
https://wiki.openwrt.org/doc/howto/build

OS X 特殊前置步骤:

参考链接:https://wiki.openwrt.org/inbox/easy.build.macosx

创建 disk image

hdiutil create -size 20g -fs "Case-sensitive HFS+" -volname OpenWrt OpenWrt.dmg
hdiutil attach OpenWrt.dmg

安装依赖

Blah-MacBook:OpenWrt Blah$ sudo port install coreutils e2fsprogs ossp-uuid asciidoc binutils \
    bzip2 fastjar flex getopt gtk2 intltool jikes hs-zlib openssl p5-extutils-makemaker python27 \
    subversion rsync ruby sdcc unzip gettext libxslt bison gawk autoconf wget gmake ncurses findutils \
    grep gnutar

由于 macport 已经过时,所以当时用的是 homebrew。(两者不要混用,选一个就好)

下载源码

目前 (2017/3/28) 用的是 15.05 的分支:

git clone -b chaos_calmer git://github.com/openwrt/openwrt.git

也可以考虑主分支,但可能不稳定:

git clone git://github.com/openwrt/openwrt.git

更新 feeds

更新

./scripts/feeds update -a

安装

./scripts/feeds install -a

配置

make menuconfig

也可以从既有的配置中导出

./scripts/diffconfig.sh > diffconfig # write the changes to diffconfig

配置

cp diffconfig .config # write changes to .config
# or > cat diffconfig >> .config to append changes to bottom of .config
make defconfig # expand to full config

编译

首次编译时有很多要下载的东西,最好找个好一些的网络环境

make V=s 2>&1 | tee build.log | grep -i error

工具链

交叉编译参考:https://wiki.openwrt.org/doc/devel/crosscompile

工具链路径
openwrt/staging_dir/toolchain-architecture_gcc-compilerver_uClibc-libcver/bin/

设置 STAGING_DIR 环境变量

# in profile
export STAGING_DIR = "{path}/openwrt/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2"

package 编译

make package/{package_path}/{clean,compile} V=99

.ipk 目标文件路径 bin/ramips/packages/base/

m2e 资源不拷贝的问题

之前一直被一个问题困扰,eclipse 运行的时候不把 resources 目录下的资源拷过去,导致运行时找不到文件。
稍微查一下就能发现 eclipse 把 resources 目录给 excludes ** 了, 查 so 可以看到这个回答

http://stackoverflow.com/questions/7754255/maven-m2eclipse-excludes-my-resources-all-the-time

大意是怕和 maven 的资源管理冲突, eclipse 把 resources 目录中所有东西都 exclude 了。当然手工把这条规则去掉能解决问题,但 maven update 一下问题又会回来了。

后来今天瞎查的时候发现 maven 的 lifecycle mapping 里 resources:resources phase 被忽略(ignore)了, 这个 phase 我之前查过恰好是拷贝资源用的。再看这条规则的来源是 workspace
于是在 eclipse 的全局 preference 里看了一下果然有这条规则,于是改完解决问题哦也

Linux 桌面歌词的搞

首先有个这个东西: http://www.sanfanling.cn/read.php?311

最开始找到的时候觉得很好用啊.

但是有几个不爽:

  1. 几个歌词下载源太烂了, 简直哭瞎.
  2. 我用的 amarok, 切换 track 的时候不能自动切歌词

搞 1

作为前虾米后网易新近网易线下用户, 拉歌词当然还是从网易拉比较好. 其实还有一个原因, 是自带的歌词引擎基本算挂完了, 太垃圾

从 https://github.com/cosven/FeelUOwn/blob/master/src/plugin/NetEaseMusic/api.py 拉到别人写的网易云音乐 api.

然后给这个东西加一个 engine (在 engines 目录下) 就行了

比如 cat engines/engine_net_ease.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import engine;
from net_ease_api import NetEase;
import json

class net_ease(engine.engine):
    def __init__(self, proxy=None, locale=None):
        self.api = NetEase( );
        self.netEncoder='utf8';

    def request(self, artist, title):
        song_list = self.api.search(artist+"+"+title);
        # print json.dumps(song_list);
        lrc_list = []
        for each in song_list["result"]["songs"]:
            try:
                lrc = self.api.get_lyric_by_musicid(each["id"])
                lrc_list.append( ("/".join(name["name"] for name in each["artists"]), each["name"], lrc["lrc"]["lyric"].encode('utf8')) )
            except Exception, e:
                pass
        return (lrc_list, False)

然后要对他的 defineThread.py 做各种更改, 比如那个什么 p.downIt 的, 去死好了, 我们不要:

--- defineThread.py     (revision 305)
+++ defineThread.py     (working copy)
@@ -41,7 +41,7 @@
                        #print originalLrc[0][2]
                        if(self.t):
                                if(len(originalLrc)==1):
-                                       originalLrc,timeOut=p.downIt(originalLrc[0][2])
+                                       originalLrc,timeOut=originalLrc[0][2], False
                                        self.sleep(1)
                                        ev=netEvent(originalLrc,timeOut,p.netEncoder)
                                        QApplication.postEvent(self.receiver,ev)
@@ -69,7 +69,7 @@
                else:
                        exec 'p=%s.%s(self.proxy)' %(self.engine,self.engine)

-               originalLrc,timeOut=p.downIt(self.url)
+               originalLrc,timeOut=self.url, False
                ev=netEvent(originalLrc,timeOut,p.netEncoder,self.fromAdvDown)
                QApplication.postEvent(self.receiver,ev)

在 engines/__init__.py 里加上我们的引擎:

import engine_net_ease as net_ease;

搞 2

这好象是 内啥 MPRIS 改接口了或者 amarok 改接口了造成的.

真恶心.

看文档有一个叫做 TrackChange 的事件专门用来表示自动播放下一首歌了.

事件加回去就行.

--- players/amarok.py   (revision 305)
+++ players/amarok.py   (working copy)
@@ -11,6 +11,7 @@
                self.process = "amarok"
                dbusPlayer.__init__(self,"amarok","org.mpris.amarok","/Player","org.freedesktop.MediaPlayer")
                self.iface.connect_to_signal("StatusChange", self.statusChanged)
+               self.iface.connect_to_signal("TrackChange", self.gaoYiXia)

        #TRACK SECTION
        def getTitle(self):
@@ -64,3 +65,7 @@
                        return
                self.callback(self.toStatus(arg))

+       def gaoYiXia(self, arg):
+               if self.callback == None:
+                       return
+               self.callback(Status().Playing)
Index: players/dbusplayer.py

最后有一个小缺憾, 老是让我们选歌词, 很烦, 第一个结果给我不就好了.

defineThread.py 的 netThread class 里有一段代码, 大意是如果只有一个结果, 就直接使用, 否则让用户选择. 把 len(结果数量) == 1 改成 >= 1 就成.

还有一个 transparency 不能穿透, 默认不是 osd+transparency+always top 的问题, 以后再搞搞看

线程池典型错误一例

撸了个线程池设施.

  1. 经一位很厉害的前辈指点, 有不少可以优化的地方
  2. 犯傻逼了:
    sem_post(&sem);
    return lockfree_queue.push(v);
    

然后在 pop 那里, 先 sem_wait() 一看, 哎! 有东西, 于是到 queue 里取, 一看, 哎! 空的! 于是线程休眠, 继续等待信号.
此时主线程姗姗来迟, 终于把 v push 到 queue 里. 客户端阻在那儿, 直到海枯石烂, 天地为之变色.

撸汇编学习

汇编一直是弱项, 于是搞了一会浅薄的内容. 做个笔记.

void foo() {
    int a, b, c, d;
}

int main() {
    foo();
    int a=10;
}

这里的流程是:

main():
把 rsp 赋值给 rbp
把 rsp – 10(或者某个数). 此时:

rbp --> |
        |
        |
rsp --> |

调用 foo

rbp(main)-->|
            |
            |
rsp/rbp  -->|

初始化 a 到 d:

rbp(main)-->| main
            |
            |
rsp/rbp  -->| foo
          a |
          b |
          c |
          d |

退出 foo 后 abcd 又无效了, 此时

rbp --> |
       a|
        |
rsp --> |
        |
        |
        |

所以想通过 foo 修改 main::a 的初始值, 改不了.
另外我试过

int main() {
    { int b = 10; }
    int a = 10;
}

也不 work, 因为 a, b 放在连续地址, 而不是 b 生命周期一结束就被覆盖了. 可能用 foo1 修改 foo2 里某个数的初始值还好说一些.
main 把 rsp 预留一段好像是因为调了其他函数 (foo) 啊, foo 不预留

rand 相关

gcc 的 rand 使用 http://en.wikipedia.org/wiki/Linear_congruential_generator 生成随机数.
从 http://cpp.indi.frih.net/blog/2014/12/the-bell-has-tolled-for-rand/ 看, time() 作为种子, 因为 time_t 最小单位是一秒, 所以一秒内跑两次程序会得到同样的结果. 验证发现确实如此…

现在的标准推荐使用 http://en.wikipedia.org/wiki/Mersenne_twister, 好多语言在用它做默认生成器.

另应该记住 VS 的 rand_max 只有 32767, 所以 rand 范围只有 32768, 这点可以用来吐槽 MS, 真是太棒了

svn 作死心得

  1. svn 不是分布式版本控制系统, 这个不是分布式很有讲究, 一个显著的表现是, commit 直接就发到服务器上了, 不会先在本地 ci 一下, 等 push 的时候再传到服务器( git way ).
  2. 如何让一个新的空分支 rebase 到另一个分支上?
    • switch, svn switch, 把当前的 working copy 设置成另一个分支. 就是, 当前是 co 的分支 A, 但通过 switch, 可以让当前的代码转成分支 B
    • merge, 把某个分支的代码 merge 到当前空分支上. 推荐使用 server url merge.

is_container 和 add 的修改版

使用boost库对is_container的修改

利用现有boost库,对owensss实现的is_container等设施做一些更新,使代码更简洁

has_xxx.hpp

#ifdef TNAME
#include <type_traits>
#include <boost/preprocessor/cat.hpp>

template <class T>
struct BOOST_PP_CAT(has_, TNAME) {
    template <class>
    static constexpr bool test(...) {
        return false;
    }

    template <class U>
    static constexpr bool test(std::remove_reference_t<typename U::TNAME>*) {
        return true;
    }

    static constexpr bool value = test<T>(nullptr);
    using type = ::bool_<value>;
};

template <class T>
constexpr bool BOOST_PP_CAT(BOOST_PP_CAT(has_, TNAME), _v)
    = BOOST_PP_CAT(has_, TNAME)<T>::value;

#undef TNAME
#endif

has_mem.hpp

#ifdef TNAME
#include <boost/preprocessor/cat.hpp>
template <class T>
struct BOOST_PP_CAT(has_mem_, TNAME) {
    struct Fallback {int TNAME;};
    struct D : T, Fallback {};
    template <typename U, U> struct check;

    template <class>
    static constexpr bool test(...) {
        return true;
    }

    template <typename U>
    static constexpr
    bool test(check<int Fallback::*, &U::TNAME>*) {
        return false;
    }

    static constexpr bool value = test<D>(nullptr);
    using type = ::bool_<value>;
};

template <class T>
constexpr bool BOOST_PP_CAT(BOOST_PP_CAT(has_mem_, TNAME), _v) = BOOST_PP_CAT(has_mem_, TNAME)<T>::value;
#undef TNAME
#endif

添加 type 使满足mpl库的需求

and.hpp

#include <boost/mpl/and.hpp>

template <typename T, typename ...Args>
struct and_ : boost::mpl::and_<T, and_<Args...> >{};

template <typename T>
struct and_<T> : T {};

由于mpl::and_ 的参数个数有限,这里利用variadic template进行扩展

is_container.hpp

#include <boost/preprocessor/cat.hpp>
#include <type_traits>
#include <boost/mpl/bool.hpp>

template<bool T>
using bool_ = boost::mpl::bool_<T>;

namespace detail {
// a preprocess iteration will be better. I an not able to and not interested in making this done
#define TNAME value_type // value type
#include "has_xxx.hpp"
//...
#define TNAME empty // empty
#include "has_mem.hpp"
}
#include "and.hpp"

template <typename T>
struct is_container 
    : and_<
        std::is_class<T>,
        detail::has_value_type<T>,
        detail::has_reference<T>,
        detail::has_const_reference<T>,
        detail::has_const_iterator<T>,
        detail::has_difference_type<T>,
        detail::has_size_type<T>,
        detail::has_mem_begin<T>,
        detail::has_mem_cbegin<T>,
        detail::has_mem_end<T>,
        detail::has_mem_cend<T>,
        detail::has_mem_size<T>,
        detail::has_mem_max_size<T>,
        detail::has_mem_empty<T> >{};

template <class T>
constexpr bool is_container_v = is_container<T>::value;

使用 and_ 来连接需求,免去 impl class 的使用

add.hpp

#include "is_container.hpp"
#include <algorithm>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>

template <class T>
using rm_ref_t = std::remove_reference_t<T>;

#define is_both_container(C1_t, C2_t) 
        is_container<C1_t>::value 
        && (is_container<C2_t>::value || std::is_array<C2_t>::value) 
        && std::is_convertible< 
            typename boost::mpl::if_< 
                std::is_array<C2_t>, 
                std::remove_extent_t<C2_t>, 
                typename C2_t::value_type>::type, 
            typename C1_t::value_type>::value

template <class C1, class C2>
std::enable_if_t<is_both_container(rm_ref_t<C1>, rm_ref_t<C2>), rm_ref_t<C1>>
add(C1&& c1, const C2& c2) {
    auto res(std::forward<C1>(c1));
    std::copy(begin(c2), end(c2), back_inserter(res));
    return res;
}

template <class C, class ... Args>
        std::enable_if_t<
            and_<
                is_container<rm_ref_t<C>>,
                std::is_convertible<rm_ref_t<Args>, typename rm_ref_t<C>::value_type>...
            >::value, rm_ref_t<C>>
add(C&& c1, Args&& ... args) {
    using Container = rm_ref_t<C>;
    Container c2 = {static_cast<typename Container::value_type>(args)...};
    return add(std::forward<C>(c1), std::move(c2));
}

使用宏来减少代码,尽管尝试过使用中间类来封装调用,但因为不满足SFINAE 的条件,failed.

If a substitution results in an invalid type or expression, type deduction fails.
An invalid type or expression is one that would be ill-formed if written using the substituted arguments.
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.

一个 通用的 add 设施 以及 is_container

写了一个通用的 add 设施, 原型如下:

  1. add(container_output, container_input) // 重载 1
    效果: 把 container_input 里的所有元素加到(push_back) container_output 里
  2. add(container_output, elements…) // 重载 2
    效果: 把所有 elements 加到(push_back) container_output 里

实现上, 使用 enable_if 做函数决议. 为此写了一个 is_container 设施判断类型是否是 container. 该设施部分遵循 Container Concept 的定义. 主要是构造啊 swap 啊几个操作符啊查起来太麻烦了. 所以没加.

首先是 is_container 的实现:

pp_cat.h, 做字符拼接.

#ifndef BOOST_PP_CAT
#    define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
#    define BOOST_PP_CAT_I(a, b) a ## b
#endif

has_xxx.h

如名所述, 判断类型 T 是否有 T::xxx 这个东西. 比如 has_value_type<vector<int>> 是 true, has_value_type<std::shared_ptr<int>> 则是 false

  • 注意没有 include guard. 这个是预处理迭代模板用
  • 注意把 reference 去掉, 因为 pointer to reference is not allowed
#ifdef TNAME
#include <type_traits>
#include "pp_cat.h"

template <class T>
struct BOOST_PP_CAT(has_, TNAME) {
        template <class U> static constexpr bool test(...) { return false; }
        template <class U> static constexpr bool test( std::remove_reference_t<typename U::TNAME> *) { return true;}

        static constexpr bool value = test<T>(0);
};

template <class T>
constexpr bool BOOST_PP_CAT(BOOST_PP_CAT(has_, TNAME), _v) = BOOST_PP_CAT(has_, TNAME)<T>::value;

#undef TNAME
#endif

has_mem.h

作用基本同上, 但是是判断是否有成员(变量或者成员函数)的. 比如 has_mem_begin<vector<int> 是 true, has_mem_begin<shared_ptr<int>> 就是 false.

代码照抄自 more c++ idioms

#ifdef TNAME
#include "pp_cat.h"

/**
 * copy from wikibook
 **/
template <class T>
struct BOOST_PP_CAT(has_mem_, TNAME) {
        struct Fallback {int TNAME;};
        struct D : T, Fallback {};
        template <typename U, U> struct check;

        template <class> static constexpr bool test(...) { return true; }
        template <class U> static constexpr bool test(check<int Fallback::*, &U::TNAME>*) { return false; }

        static constexpr bool value = test<D>(0);
};

template <class T>
constexpr bool BOOST_PP_CAT(BOOST_PP_CAT(has_mem_, TNAME), _v) = BOOST_PP_CAT(has_mem_, TNAME)<T>::value;
#undef TNAME
#endif

然后是 is_container.hpp

基本上就是查了一番它 typedef 的类型和成员函数.
有一点比较奇怪的是 is_container_v 在模板里面不能用. 也不明白是为什么.

#include <type_traits>

namespace detail {
// a preprocess iteration will be better. I an not able to and not interested in making this done
#define TNAME value_type // value type
#include "has_xxx.h"
#define TNAME reference // reference
#include "has_xxx.h"
#define TNAME const_reference // const_reference
#include "has_xxx.h"
#define TNAME iterator // iterator
#include "has_xxx.h"
#define TNAME const_iterator // const_iterator
#include "has_xxx.h"
#define TNAME difference_type // difference_type
#include "has_xxx.h"
#define TNAME size_type // size_type
#include "has_xxx.h"
#define TNAME begin // begin
#include "has_mem.h"
#define TNAME cbegin // cbegin
#include "has_mem.h"
#define TNAME end // end
#include "has_mem.h"
#define TNAME cend // cend
#include "has_mem.h"
#define TNAME size // size
#include "has_mem.h"
#define TNAME max_size // max_size
#include "has_mem.h"
#define TNAME empty // empty
#include "has_mem.h"
}

template <bool, class>
struct is_container_impl {
        static constexpr bool value = false;
};

template <class T>
struct is_container_impl<true, T> {
        static constexpr int value =
                   detail::has_value_type_v<T>
                && detail::has_reference_v<T>
                && detail::has_const_reference_v<T>
                && detail::has_const_iterator_v<T>
                && detail::has_difference_type_v<T>
                && detail::has_size_type_v<T>
                && detail::has_mem_begin_v<T>
                && detail::has_mem_cbegin_v<T>
                && detail::has_mem_end_v<T>
                && detail::has_mem_cend_v<T>
                && detail::has_mem_size_v<T>
                && detail::has_mem_max_size_v<T>
                && detail::has_mem_empty_v<T>;
};

template <class T>
struct is_container : is_container_impl<std::is_class<T>::value, T> { };

template <class T>
constexpr bool is_container_v = is_container<T>::value;

这样一个 is_container 设施就算好了. 测试代码如下:

#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#include <bitset>
#include <array>
#include "is_container.hpp"

struct foo {
        typedef int value_type;
        void begin();
};

struct bar {};

class my_intv {
        public:
                typedef int value_type;
                typedef value_type& reference;
                typedef const value_type& const_reference;
                typedef int* iterator;
                typedef const iterator const_iterator;
                typedef iterator difference_type;
                typedef int size_type;
        public:
                iterator begin();
                const_iterator cbegin() const;
                const_iterator begin() const;
                iterator end();
                const_iterator cend() const;
                const_iterator end() const;
                size_type size() const;
                size_type max_size() const;
                bool empty() const;
};

class my_intv_fake_t : my_intv {
        private:
                typedef int size_type;
};

class my_intv_fake_m : my_intv {
        private:
                size_type size() const;
};

using namespace std;

int main() {
        using T = vector<int>;
        using arr = int[10];
        cout << "intt" << is_container_v<int> << endl;
        cout << "vectort" << is_container_v<const vector<int>> << endl;
        cout << "dequet" << is_container_v<deque<int>> << endl;
        cout << "queuet" << is_container_v<queue<int>> << endl;
        cout << "bitsett" << is_container_v<bitset<12>> << endl;
        cout << "mapt" << is_container_v<map<int, char>> << endl;
        cout << "arrayt" << is_container_v<array<int, 12>> << endl;
        cout << "my_intvt" << is_container_v<my_intv> << endl;
        cout << "my_intv_fake_tt" << is_container_v<my_intv_fake_t> << endl;
        cout << "my_intv_fake_mt" << is_container_v<my_intv_fake_m> << endl;
}

最后用 enable_if 实现 generic add.

原型 1:

add(ContainerOut& out, const ContainerIn& in)

条件是

  1. ContainerOut 是 Container 类型(通过 is_container 判断)
  2. ContainerIn 是 Container 类型或者 array 类型(通过 is_array 判断)
  3. ContainerIn 的 value_type 能转换成 ContainerOut 的 value_type (通过 is_convertible 判断)

原型 2:

add(ContainerOut& out, Elements&& ... in)

条件是

  1. ContainerOut 是 Container 类型
  2. 每一个 Element 都能转换成 ContainerOut 的 value_type

最终产物如下:

#include "is_container.hpp"
#include <algorithm>
#include <type_traits>

template <class T>
using rm_ref = std::remove_reference_t<T>;

template <class COut, class CIn>
std::enable_if_t<
        is_container<rm_ref<COut>>::value // Out type is a container
        && ( is_container<rm_ref<CIn>>::value || std::is_array<rm_ref<CIn>>::value ) // In type is a container or an array
        && ( std::is_array<rm_ref<CIn>>::value ? // value_type of in type is same or convertible to value_type of out type
                        std::is_convertible<std::remove_extent_t<rm_ref<CIn>>, typename rm_ref<COut>::value_type>::value // array
                  : std::is_convertible<typename rm_ref<CIn>::value_type, typename rm_ref<COut>::value_type>::value // container
           )
>
add(COut& out, const CIn& in) {
        std::copy(begin(in), end(in), back_inserter(out));
}

template <bool first, bool ... args>
struct all_true {
        static constexpr bool value = first ? all_true<args...>::value : false;
};

template <bool last>
struct all_true<last> {
        static constexpr bool value = last;
};

template <class COut, class ... Args>
        std::enable_if_t<
                is_container<rm_ref<COut>>::value // Out type is a container
                && all_true< // Arg types all convertible to outtype
                        std::is_convertible< rm_ref<Args>, typename rm_ref<COut>::value_type >::value...
                >::value
        >
add(COut& out, Args&& ... in) {
        // initializer list don't implement move semantics
        auto tmp = {static_cast<typename rm_ref<COut>::value_type>(in)...}; // Don't know best practice in this case
        std::copy(begin(tmp), end(tmp), back_inserter(out));
}

new 在 lambda

看到一个问题,如何把 lambda 弄到 new 出来的地址上。

一开始的想法是:lambda 在声明的时候就已经是 rv 了,而 trivial move ctor 是 优先 move 的 bitwise copy,那肯定搞不定啊。

举例说:

something = move([]{}); // 此时,某个匿名函数已经构造完毕,所以 这里的实际代码是:

something.m_a = move(__unnamed.m_a);
something.m_b = move(__unnamed.m_b);
...

等于白搭。

但两次询问问题人后其确定 void* p = (void*) new sometype([]{}); 的语法是能够把 lambda 的构造弄到 new 出来的内存上的。于是开干吧。

首先查阅 gcc 源码,得知其 lambda 命名规则是 __lambda%d,%d 跟第 lambdacnt 个。所以 第 1 个 lambda 的类的名字是 __lambda0

int main() {
    class __lambda0;
    void* p = (void*) new __lambda0([]{});
    (*(__lambda0*)p)();
}

这样。

然后查阅汇编代码,实际上因为我对汇编不是很熟,对比了两份。

——— 1 ————

#include <iostream>

int main() {
    int a = 10, b = 20, c = 30, d = 40, e = 50;
    class __lambda0;
    auto f = [a, b, c, d, e]{static int a; static int c; int b = 1025;};
    f();
}

———- 2 ————-

#include <iostream>

int main() {
    int a = 10, b = 20, c = 30, d = 40, e = 50;
    class __lambda0;
    void* p = (void*) new __lambda0([a, b, c, d, e]{static int a; static int c; int b = 1025;});
    (*(__lambda0*)p)();
}

对照着看:

———- 1 ————-

_main:
LFB1139:
.cfi_startproc
pushl   %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl    %esp, %ebp
.cfi_def_cfa_register 5
andl    $-16, %esp
subl    $48, %esp
call    ___main
movl    $10, 44(%esp)
movl    $20, 40(%esp)
movl    $30, 36(%esp)
movl    $40, 32(%esp)
movl    $50, 28(%esp)
movl    44(%esp), %eax
movl    %eax, 8(%esp)
movl    40(%esp), %eax
movl    %eax, 12(%esp)
movl    36(%esp), %eax
movl    %eax, 16(%esp)
movl    32(%esp), %eax
movl    %eax, 20(%esp)
movl    28(%esp), %eax
movl    %eax, 24(%esp)
leal    8(%esp), %eax
movl    %eax, %ecx
call    __ZZ4mainENKUlvE_clEv # call lambda func

———- 2 ————-

_main:
LFB1139:
.cfi_startproc
pushl   %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl    %esp, %ebp
.cfi_def_cfa_register 5
andl    $-16, %esp
subl    $48, %esp
call    ___main
movl    $10, 44(%esp)
movl    $20, 40(%esp)
movl    $30, 36(%esp)
movl    $40, 32(%esp)
movl    $50, 28(%esp)
movl    $20, (%esp)
call    __Znwj # new
movl    44(%esp), %edx
movl    %edx, (%eax)
movl    40(%esp), %edx
movl    %edx, 4(%eax)
movl    36(%esp), %edx
movl    %edx, 8(%eax)
movl    32(%esp), %edx
movl    %edx, 12(%eax)
movl    28(%esp), %edx
movl    %edx, 16(%eax)
movl    %eax, 24(%esp)
movl    24(%esp), %eax
movl    %eax, %ecx
call    __ZZ4mainENKUlvE_clEv # call lambda func

可以看到

非 new 的版本里:

movl    $10, 44(%esp) # *(44+esp) = 10 // a=10
...
# 开始初始化
movl    44(%esp), %eax # eax = *(44+esp) // eax = a;
movl    %eax, 8(%esp) # *(8+esp) = eax; # 这里初始化 __lambda0 // __lambda0.a = eax;

new 的版本里:

movl    $10, 44(%esp) # *(44+esp) = 10; // a = 10;

call    __Znwj # new(20) 这个 20 装在 *(esp) 里 // new(20);
movl    44(%esp), %edx # edx = *(44+esp) // edx = a;
movl    %edx, (%eax) # *eax = edx; // 这里的 eax 就是 new 出来的内存的起始地址(是规定)// __lambda0.a = edx

我在这里的判断中犯的错误是,把 lambda 当成如同 std 里面的类型了。但 lambda 不是的。它是一种内置类型,可以享受内置类型带来的各种优越条件。同样的例子可以看:

int* a = new int(10); 

谁都不可能觉得这个 10 是先弄出一个临时量再被 copy 到 *a 中的。

补充两个:

  1. 至少 gcc 的实现里,栈是以 16byte 为单位增长的。
  2. new(size) 的 size 是 long long,放在 0(esp);