青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

loop_in_codes

低調做技術__歡迎移步我的獨立博客 codemaro.com 微博 kevinlynx

基于內存查看STL常用容器內容

有時候在線上使用gdb調試程序core問題時,可能沒有符號文件,拿到的僅是一個內存地址,如果這個指向的是一個STL對象,那么如何查看這個對象的內容呢?

只需要知道STL各個容器的數據結構實現,就可以查看其內容。本文描述了SGI STL實現中常用容器的數據結構,以及如何在gdb中查看其內容。

string

string,即basic_string bits/basic_string.h

mutable _Alloc_hider  _M_dataplus;
    ... 
      const _CharT*
      c_str() const
      { return _M_data(); }
    ...    
      _CharT*
      _M_data() const 
      { return  _M_dataplus._M_p; }

    ...
      struct _Alloc_hider : _Alloc
      {
    _Alloc_hider(_CharT* __dat, const _Alloc& __a)
    : _Alloc(__a), _M_p(__dat) { }

    _CharT* _M_p; // The actual data.
      };
   
      size_type
      length() const
      { return _M_rep()->_M_length; }

      _Rep*
      _M_rep() const
      { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }

      ...
       struct _Rep_base
      {
    size_type       _M_length;
    size_type       _M_capacity;
    _Atomic_word        _M_refcount;
      };

      struct _Rep : _Rep_base

即,string內有一個指針,指向實際的字符串位置,這個位置前面有一個_Rep結構,其內保存了字符串的長度、可用內存以及引用計數。當我們拿到一個string對象的地址時,可以通過以下代碼獲取相關值:

void ds_str_i(void *p) {
        char **raw = (char**)p;
        char *s = *raw;
        size_t len = *(size_t*)(s - sizeof(size_t) * 3);
        printf("str: %s (%zd)\n", s, len);
    }

    size_t ds_str() {
        std::string s = "hello";
        ds_str_i(&s);
        return s.size();
    }

在gdb中拿到一個string的地址時,可以以下打印出該字符串及長度:

(gdb) x/1a p
0x7fffffffe3a0: 0x606028
(gdb) p (char*)0x606028
$2 = 0x606028 "hello"
(gdb) x/1dg 0x606028-24
0x606010:       5

vector

眾所周知vector實現就是一塊連續的內存,bits/stl_vector.h

template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector : protected _Vector_base<_Tp, _Alloc>

    ...
    template<typename _Tp, typename _Alloc>
    struct _Vector_base
    {
      typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;

      struct _Vector_impl
      : public _Tp_alloc_type
      {
    _Tp*           _M_start;
    _Tp*           _M_finish;
    _Tp*           _M_end_of_storage;
    _Vector_impl(_Tp_alloc_type const& __a)
    : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
    { }
      };


      _Vector_impl _M_impl;

可以看出sizeof(vector<xxx>)=24,其內也就是3個指針,_M_start指向首元素地址,_M_finish指向最后一個節點+1,_M_end_of_storage是可用空間最后的位置。

iterator
      end()
      { return iterator (this->_M_impl._M_finish); }
      const_iterator
      ...
      begin() const
      { return const_iterator (this->_M_impl._M_start); }
      ...
      size_type
      capacity() const
      { return size_type(const_iterator(this->_M_impl._M_end_of_storage)
             - begin()); }

可以通過代碼從一個vector對象地址輸出其信息:

template <typename T>
    void ds_vec_i(void *p) {
        T *start = *(T**)p;
        T *finish = *(T**)((char*)p + sizeof(void*));
        T *end_storage = *(T**)((char*)p + 2 * sizeof(void*));
        printf("vec size: %ld, avaiable size: %ld\n", finish - start, end_storage - start); 
    }

    size_t ds_vec() {
        std::vector<int> vec;
        vec.push_back(0x11);
        vec.push_back(0x22);
        vec.push_back(0x33);
        ds_vec_i<int>(&vec);
        return vec.size();
    }

使用gdb輸出一個vector中的內容:

(gdb) p p
$3 = (void *) 0x7fffffffe380
(gdb) x/1a p
0x7fffffffe380: 0x606080
(gdb) x/3xw 0x606080
0x606080:       0x00000011      0x00000022      0x00000033

list

眾所周知list被實現為一個鏈表。準確來說是一個雙向鏈表。list本身是一個特殊節點,其代表end,其指向的下一個元素才是list真正的第一個節點:

bits/stl_list.h

bool
      empty() const
      { return this->_M_impl._M_node._M_next == &this->_M_impl._M_node; }

      const_iterator
      begin() const
      { return const_iterator(this->_M_impl._M_node._M_next); }

      iterator
      end()
      { return iterator(&this->_M_impl._M_node); }

      ...

    struct _List_node_base
    {
        _List_node_base* _M_next;   ///< Self-explanatory
        _List_node_base* _M_prev;   ///< Self-explanatory
        ...
    };
         
    template<typename _Tp>
    struct _List_node : public _List_node_base
    {
      _Tp _M_data;                ///< User's data.
    };
      
    template<typename _Tp, typename _Alloc>
    class _List_base
    {
        ...
      struct _List_impl
      : public _Node_alloc_type
      {
    _List_node_base _M_node;
        ...
      };

      _List_impl _M_impl;

          
    template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class list : protected _List_base<_Tp, _Alloc>

所以sizeof(list<xx>)=16,兩個指針。每一個真正的節點首先是包含兩個指針,然后是元素內容(_List_node)。

通過代碼輸出list的內容:

#define NEXT(ptr, T) do { \
        void *n = *(char**)ptr; \
        T val = *(T*)((char**)ptr + 2); \
        printf("list item %p val: 0x%x\n", ptr, val); \
        ptr = n; \
    } while (0)

    template <typename T>
    void ds_list_i(void *p) {
        void *ptr = *(char**)p;

        NEXT(ptr, T);
        NEXT(ptr, T);
        NEXT(ptr, T);
    }

    size_t ds_list() {
        std::list<int> lst;
        lst.push_back(0x11);
        lst.push_back(0x22);
        lst.push_back(0x33);
        ds_list_i<int>(&lst);
        return lst.size();
    }

在gdb中可以以下方式遍歷該list:

(gdb) p p
$4 = (void *) 0x7fffffffe390
(gdb) x/1a p
0x7fffffffe390: 0x606080
(gdb) x/1xw 0x606080+16         # 元素1 
0x606090:       0x00000011
(gdb) x/1a 0x606080
0x606080:       0x6060a0
(gdb) x/1xw 0x6060a0+16         # 元素2
0x6060b0:       0x00000022

map

map使用的是紅黑樹實現,實際使用的是stl_tree.h實現:

bits/stl_map.h

typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
               key_compare, _Pair_alloc_type> _Rep_type;
    ...
     _Rep_type _M_t;
    ... 

      iterator
      begin()
      { return _M_t.begin(); }

bits/stl_tree.h

struct _Rb_tree_node_base
      {
        typedef _Rb_tree_node_base* _Base_ptr;
        typedef const _Rb_tree_node_base* _Const_Base_ptr;

        _Rb_tree_color  _M_color;
        _Base_ptr       _M_parent;
        _Base_ptr       _M_left;
        _Base_ptr       _M_right;
        
        ...
      };

    template<typename _Val>
    struct _Rb_tree_node : public _Rb_tree_node_base
    {
      typedef _Rb_tree_node<_Val>* _Link_type;
      _Val _M_value_field;
    };


    template<typename _Key_compare,
           bool _Is_pod_comparator = std::__is_pod<_Key_compare>::__value>
        struct _Rb_tree_impl : public _Node_allocator
        {
      _Key_compare      _M_key_compare;
      _Rb_tree_node_base    _M_header;
      size_type         _M_node_count; // Keeps track of size of tree.
      ...
        }
    
    _Rb_tree_impl<_Compare> _M_impl;
    ...

      iterator
      begin()
      {
    return iterator(static_cast<_Link_type>
            (this->_M_impl._M_header._M_left));
      }

所以可以看出,大部分時候(取決于_M_key_compare) sizeof(map<xx>)=48,主要的元素是:

_Rb_tree_color  _M_color; // 節點顏色
        _Base_ptr       _M_parent; // 父節點
        _Base_ptr       _M_left; // 左節點
        _Base_ptr       _M_right; // 右節點
        _Val            _M_value_field // 同list中節點技巧一致,后面是實際的元素

同list中的實現一致,map本身作為一個節點,其不是一個存儲數據的節點,

_Rb_tree::end

iterator
      end()
      { return iterator(static_cast<_Link_type>(&this->_M_impl._M_header)); }

由于節點值在_Rb_tree_node_base后,所以任意時候拿到節點就可以偏移這個結構體拿到節點值,節點的值是一個pair,包含了key和value。

在gdb中打印以下map的內容:

size_t ds_map() {
        std::map<std::string, int> imap;
        imap["abc"] = 0xbbb;
        return imap.size();
    }
(gdb) p/x &imap
$7 = 0x7fffffffe370
(gdb) x/1a (char*)&imap+24       # _M_left 真正的節點
0x7fffffffe388: 0x606040          
(gdb) x/1xw 0x606040+32+8        # 偏移32字節是節點值的地址,再偏移8則是value的地址
0x606068:       0x00000bbb
(gdb) p *(char**)(0x606040+32)   # 偏移32字節是string的地址
$8 = 0x606028 "abc"

或者很多時候沒有必要這么裝逼+蛋疼:

(gdb) p *(char**)(imap._M_t._M_impl._M_header._M_left+1)
$9 = 0x606028 "abc"
(gdb) x/1xw (char*)(imap._M_t._M_impl._M_header._M_left+1)+8
0x606068:       0x00000bbb

posted on 2014-12-03 22:08 Kevin Lynx 閱讀(3870) 評論(2)  編輯 收藏 引用 所屬分類: c/c++

評論

# re: 基于內存查看STL常用容器內容 2014-12-04 18:57 xxoo

問一下,既然string的結構類型是
(size_t,size_t,size_t,char*)
為啥string地址里前4個自己是char*的地址,應該是size_t的前4個字節才對啊?  回復  更多評論   

# re: 基于內存查看STL常用容器內容 2014-12-07 18:27 Kevin Lynx

@xxoo
"即,string內有一個指針,指向實際的字符串位置,這個位置前面有一個_Rep結構,其內保存了字符串的長度、可用內存以及引用計數。"  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产一区二区精品在线观看| 亚洲免费在线电影| 久久亚洲色图| 欧美一区三区二区在线观看| 国产精品素人视频| 久久精品亚洲乱码伦伦中文| 久久久久久久一区| 日韩视频免费| 亚洲天堂视频在线观看| 国产精品久久久久一区二区三区共 | 久久国产色av| 欧美肉体xxxx裸体137大胆| 在线亚洲一区观看| 性欧美办公室18xxxxhd| 一区二区亚洲| 亚洲精品孕妇| 国产亚洲欧美一区二区三区| 欧美激情第9页| 国产精品美女久久久久久免费 | 亚洲第一成人在线| 亚洲精品一区在线观看| 国产亚洲精品资源在线26u| 免费日韩视频| 国产精品剧情在线亚洲| 免费不卡亚洲欧美| 国产精品乱子乱xxxx| 美女尤物久久精品| 国产精品观看| 欧美激情中文字幕乱码免费| 国产精品一区二区久久精品 | 亚洲已满18点击进入久久| 久久成人精品视频| 亚洲一区二区三区成人在线视频精品 | 久久香蕉国产线看观看av| 欧美日韩高清一区| 久久久亚洲高清| 欧美性猛交xxxx乱大交退制版| 久久久久久999| 欧美性色综合| 亚洲韩国日本中文字幕| 欧美日韩一区二区在线播放| 噜噜噜噜噜久久久久久91 | 欧美福利网址| 久久手机精品视频| 国产精品网站在线| 一本大道久久精品懂色aⅴ| 亚洲电影成人| 欧美亚洲自偷自偷| 午夜精品影院| 欧美日韩精品免费在线观看视频| 欧美 日韩 国产精品免费观看| 国产毛片一区二区| 一区二区三区你懂的| 91久久久久久国产精品| 久久国产99| 久久精品首页| 国产视频综合在线| 亚洲欧美日韩第一区| 亚洲欧美日韩中文播放| 国产精品theporn| 一本高清dvd不卡在线观看| 亚洲巨乳在线| 欧美精品在线免费观看| 欧美国产精品专区| 亚洲第一色在线| 麻豆精品视频| 亚洲国产一区二区精品专区| 欧美午夜激情在线| 亚洲国产综合视频在线观看| 国产在线视频欧美一区二区三区| 亚洲伊人第一页| 亚洲欧美日韩人成在线播放| 国产精品伦一区| 亚洲欧美国产日韩天堂区| 校园春色国产精品| 国产精品久久久久久亚洲调教 | 亚洲欧美在线网| 国产日韩成人精品| 久久成人免费日本黄色| 久久综合网络一区二区| 亚洲国产欧美在线人成| 美国十次了思思久久精品导航| 欧美激情精品久久久久久免费印度| 亚洲国产精品一区制服丝袜| 欧美精品久久久久久久免费观看 | 亚洲综合色噜噜狠狠| 国产精品人人做人人爽| 久久久99免费视频| 亚洲高清免费在线| 亚洲少妇一区| 国产视频久久久久| 免费短视频成人日韩| 日韩视频在线一区二区三区| 欧美在线黄色| 亚洲高清久久| 国产精品theporn| 久久躁日日躁aaaaxxxx| 99伊人成综合| 久久夜色精品一区| 亚洲午夜电影网| 国语精品中文字幕| 欧美手机在线| 久久久久久久久久久久久久一区| 亚洲国产精品久久| 久久精品国产亚洲一区二区| 亚洲欧洲一区| 国产在线一区二区三区四区| 欧美日韩国产首页| 久久人人看视频| 亚洲先锋成人| 亚洲黄色性网站| 久久精品国产久精国产思思| 日韩视频免费看| 一区二区在线观看av| 欧美性生交xxxxx久久久| 欧美α欧美αv大片| 性欧美精品高清| av成人黄色| 亚洲激情二区| 欧美电影免费观看网站| 久久久精品免费视频| 亚洲一区二区精品在线观看| 亚洲福利国产| 国内成+人亚洲| 国产精品久久久久影院色老大| 欧美激情一区二区三区高清视频| 久久精品免费电影| 亚洲欧美日本国产专区一区| 亚洲欧洲三级| 亚洲国内欧美| 亚洲日本久久| 亚洲欧洲午夜| 亚洲日本理论电影| 亚洲精品一区二区网址| 欧美成人综合一区| 欧美电影在线观看完整版| 久久成人av少妇免费| 欧美一级大片在线免费观看| 正在播放欧美视频| 久久久人成影片一区二区三区| 亚洲电影第1页| 久久综合精品国产一区二区三区| 亚洲欧美日韩在线播放| 亚洲午夜一级| 午夜精品视频网站| 亚洲欧美日韩一区二区在线 | 91久久国产精品91久久性色| 亚洲国产高清在线观看视频| 一区二区三区在线观看视频| 一区二区三区自拍| 亚洲人成小说网站色在线| 91久久精品一区二区三区| 亚洲欧洲日夜超级视频| 亚洲国产精品一区二区第一页| 亚洲激情一区| 亚洲天堂av在线免费| 亚洲视频综合| 久久国产主播| 免费成人性网站| 亚洲电影av| 亚洲视频久久| 欧美诱惑福利视频| 狼狼综合久久久久综合网| 你懂的国产精品| 欧美视频中文字幕| 国产一区二区三区在线观看免费| 伊人久久婷婷| 夜夜夜精品看看| 欧美伊人精品成人久久综合97| 久久久久久噜噜噜久久久精品| 男人插女人欧美| 亚洲欧洲视频在线| 午夜在线a亚洲v天堂网2018| 久久亚洲精品欧美| 欧美午夜久久| 亚洲丁香婷深爱综合| 亚洲婷婷免费| 欧美~级网站不卡| 宅男66日本亚洲欧美视频| 欧美在线一区二区| 欧美日韩国产另类不卡| 国产一区二区三区久久久| 亚洲精品女av网站| 久久精品成人| 一本色道久久综合狠狠躁篇怎么玩| 欧美一区二区三区免费看| 欧美激情精品久久久久久变态| 国产欧美精品一区| 亚洲清纯自拍| 久久久99国产精品免费| 99riav久久精品riav| 久久夜色精品一区| 国产精品日本一区二区| 亚洲精品在线免费观看视频| 欧美一区二区三区免费看| 亚洲国产精品黑人久久久| 久久久久久久久岛国免费| 国产欧美高清| 亚洲欧美日韩在线| 亚洲第一伊人|