渔舟唱晚的天空
——welkinwalker的遐想

字符指针和字符数组有一个小的区别:

字符指针是一个指针变量,他是要占用空间的,这个空间的大小取决于机器是多少位的64位的就要占用8个字节,因为他是地址,64位系统的地址是用64位来表示的

字符数组虽然在使用上类似上像是在使用字符指针,然而实际上,本质上他只不过是编译器在内存中做的标记,字符数组本身不占用任何空间。

 

所以,下面的struct在64位机器上的大小是16个字节。

struct test{
    int32_t a;
    
char* buff;
    
char buf[];
}; 

 

int32_t a; 应当使用4个字节,但是64位机器要做64位对其,所以占用了8个字节

char* buff; buff是一个指针,又占用一个64为的地址空间,再加8个字节

char buf[]; 这个东西一个空间也不占用,他就像是一个隐形的字符指针

 

这一点在redis的

Simple Dynamic Strings中得到了出色的应用,参考:http://redis.io/topics/internals-sds

 

修改了的代码可以看到效果: 

#include <stdio.h>
#include 
<iostream>

using namespace std;

typedef 
char *sds;
struct sdshdr {
    
long len;
    
long free;
    
char buf[];
};

sds sdsnewlen(
const void *init, size_t initlen) {
    
struct sdshdr *sh;

    sh 
= (sdshdr*)malloc(sizeof(struct sdshdr)+initlen+1);
    
if (sh == NULL) return NULL;
    sh
->len = initlen;
    sh
->free = 0;
    
if (initlen) {
        
if (init) memcpy(sh->buf, init, initlen);
        
else memset(sh->buf,0,initlen);
    }   
    sh
->buf[initlen] = '\0';

    printf(
"addr of len : 0x%X\n",&sh->len);
    printf(
"addr of free: 0x%X\n",&sh->free);
    printf(
"addr of buf : 0x%X\n",&sh->buf);
    printf(
"addr of sh  : 0x%X\n",sh);
    
return (char*)sh->buf;
}
size_t sdslen(
const sds s) {
    printf(
"addr of s   : 0x%X\n",s);
    
struct sdshdr *sh = (sdshdr*) (s-(sizeof(struct sdshdr)));
    printf(
"addr of sh  : 0x%X\n",sh);
    
return sh->len;
}
main()
{
    sds str 
= sdsnewlen("redis"5);
    cout
<<"-----------------------"<<endl;
    cout
<<(sdslen(str))<<endl;;
}

以上代码的输出是: 

addr of len : 0xE8D3010
addr of free: 
0xE8D3018
addr of buf : 
0xE8D3020
addr of sh  : 
0xE8D3010
-----------------------
addr of s   : 
0xE8D3020
addr of sh  : 
0xE8D3010
5

在这个sdshdr中,buf就好像是一个隐藏的指针,他不参与大小的运算(其实根本没有给他分配内存空间),但是却保存着sds最重要的数据内容。

相关的描述也可以在下面的文章中看到:

http://www.cnblogs.com/welkinwalker/archive/2011/01/05/1926203.html 


 

 

posted on 2011-09-06 11:57  welkinwalker  阅读(1485)  评论(0编辑  收藏  举报