2012年6月5日星期二

把一个C的原生二维数组转换成gsl_matrix

如果你希望所有操作在栈上进行,可以考虑这样,利用C的原生二维数组的内存布局和gsl_matrix对内存布局的假设一致:每一行的内容连续存储。


#include <stdio.h>
#include <gsl/gsl_matrix.h>

#define init_matrix(src, dst) \
    gsl_matrix dst; \
    dst.size1 = sizeof(src) / sizeof(src[0]); \
    dst.tda = dst.size2 = sizeof(src[0]) / sizeof(src[0][0]); \
    dst.data = (double*)(void*)src; \
    dst.block = NULL; dst.owner = false;
    
int main() 
{
    double x[3][4];
    for(int i=0;i<3;++i)for(int j=0;j<4;++j)x[i][j]=1+i+0.1*(1+j);
    init_matrix(x, a);
    gsl_matrix_scale(&a, 100);
    gsl_matrix_fprintf(stdout, &a, "%g");
}

结果

110
120
130
140
210
220
230
240
310
320
330
340

2012年6月3日星期日

虚继承的内存布局

一天我一同事向我推荐了一本书,讲C++对象模型的。
周五下班后,我和另一个同事做了个试验:

#include <stdio.h>
struct B{   char c;};
struct B1: virtual B{   char b1;};
struct B2: virtual B{   char b2;};
struct D : public B1, public B2, virtual B{ char d;};

int main()
{
    D _d;
    D* d = &_d;
    d->d = 'd';d->b1='1';d->b2='2';d->c='c';
    B2* b2 = d;
    B1* b1 = d;
    B* b = d;
    printf("sizeof(B), sizeof(B1), sizeof(B2), sizeof(D) = %d %d %d %d\n", sizeof(B), sizeof(B1), sizeof(B2), sizeof(D));
    printf("d %p %p %d %d %d %d\n", d, *(long*)d, long(&d->c) - long(d), long(&d->b1) - long(d), long(&d->b2) - long(d), long(&d->d)-long(d) );
    printf("b1 c,b1 = %c %c\n", b1->c, b1->b1);
    printf("b1 %p %p %d %d\n", b1, *(long*)b1, long(&b1->c) - long(b1), long(&b1->b1) - long(b1) );
    printf("b2 c,b2 = %c %c\n", b2->c, b2->b2);
    printf("b2 %p %p %d %d\n", b2, *(long*)b2, long(&b2->c) - long(b2), long(&b2->b2) - long(b2) );
    printf("b c %c\n", b->c);
    printf("b %p %d\n", b, long(&b->c)-long(b) );
    return 0;
}

g++编译后运行结果

sizeof(B), sizeof(B1), sizeof(B2), sizeof(D) = 1 16 16 32
d 0x7ffff7897d60 0x401178 26 8 24 25
b1 c,b1 = c 1
b1 0x7ffff7897d60 0x401178 26 8
b2 c,b2 = c 2
b2 0x7ffff7897d70 0x401190 10 8
b c c
b 0x7ffff7897d7a 0


貌似是有32个字节的连续内存。d和b1都指向这段内存的首地址,b2指向偏移量为16字节的位置。b指向偏移量为26字节的位置。
前16个字节:前8个字节是B1的虚表的指针,第9个字节存了成员b1,然后是7个字节的padding。
后16个字节:前8个字节是B2的虚表的指针,第9个字节存了成员b2,第10个字节存了成员d,第11个字节存了成员c,然后是5个字节的padding。
内存布局的顺序大约是:第一个父类成员、第二个父类成员、当前类成员、公共虚继承的祖父类成员。
另外一个发现是:指针的类型转换后可能导致指针本身的值的变化,因为子类指针和父类指针可能指向同一段连续内存的不同位置。