Kelvin You wrote:
 We use
        proto_tree_add_text(tree, tvb, offset,  6,  "MAC Address %d: 
%s",  index, ether_to_str(src_addr));
 to add a formated text to the tree item.
Well, you also have to get "src_addr" in the first place:
	src_addr = tvb_get_ptr(tvb, offset, 6);
 Also we can use:
...
    static hf_register_info hf[] =
    {
        /* ----------     Demultiplex Layer    ------------- */
        { &hf_xxx_macaddr,
            { "MAC Address",          "xxx.macaddr",
            FT_ETHER, BASE_NONE, NULL, 0x00,
            "", HFILL }
        },
 
proto_tree_add_ether_format(tree, hf_xxx_macaddr, tvb, offset,  6,  
ether_to_str(src_addr), "MAC Address %d: %s",  index, 
ether_to_str(src_addr));
No.  You can, however, use
	src_addr = tvb_get_ptr(tvb, offset, 6);
	proto_tree_add_ether_format(tree, hf_xxx_macaddr, tvb, offset, 6, 
src_addr, "MAC Address %d: %s", index, ether_to_str(src_addr));
You supply the raw MAC address as the value for hf_xxx_macaddr, not the 
string generated from the MAC address.
what's the difference between the two way?
It seems the the second method have more redundancy. why not substitute 
the second way with the first one always ?
The first way puts an unnamed entry into the protocol tree; you cannot 
write a display filter that matches packets where one of the MAC 
addresses in the list happens to be equal to a particular value.  The 
second way puts a *named* entry, so you can do
	xxx.macaddr == 00:00:08:00:00:0c
to match packets that have one of the "xxx.macaddr" fields equal to 
00:00:08:00:00:0c.
If you have only *one* MAC address, rather than a *sequence* of them, 
you could do
	proto_tree_add_item(tree, hf_xxx_macaddr, offset, 6, FALSE);
which has even less redundancy than the proto_tree_add_text() call - you 
only specify "tvb" and "offset" once, and you don't specify "MAC 
Address" or "ether_to_str()", or call "tvb_get_ptr()", at all.
If it's very common that people have arrays of identical items, we 
could, I guess, add a "proto_tree_add_array_element_item()" or something 
such as that - you'd also pass it "index", and it'd put the "%d" (or, 
more likely, "%u") after the field name.