OOC-GCC 简介

Posted on Tue, 25 Jan 2011 05:08:08 -1100

OOC-GCC 概述

 

下载地址

http://code.google.com/p/ooc-gcc/downloads/list

 

其实这还是我对用C语言进行OO方式编程的一些尝试,最早的时候我在SF建了一个叫JCOOP的项目,后来搬到GOOGLE CODE

 

不过随着不断的改进,也对OO有了进一步的理解,

 

在这里先谈一下现在我对OO的理解,

 

所谓OO,本质是对象驱动型编程模式,其核心在于抽象,并将代码封装使之更易于复用.

 

所以说你用结构体来抽象描述某种事物并不意味着你的代码就不是OO的,所以说用C也是可以写出OO的代码的.

 

有人或许会更仔细的区分OO和OB,认为只有支持了多态,RTTI这些儿玩意儿的才是OO,其它的只能是OB

 

[※O→oriented,B→based]

 

我不想去争论这些没有太大意义的概念,因为C语言本身不是OO的语言.

 

不过话说回来,计算机的执行过程在逻辑上都本质是过程化的,因为汇编是过程的,机器码也是过程的.

 

而那些OO的语言只不过是编译器帮助完成了一些迷惑性的工作,帮你完成了内存分布,访问控制等的跑龙套的活而已.

 

无论何种类型的语言,执行过程都会遵循一定的顺序,所以说像C这类语言骨子里并不输给CPP,JAVA,

 

反倒是一些很高级的语言,引入了过多的语法糖,深入学习后总会感到有些瑕疵.

 

下面言归正传,

 

用C去模拟OO[这里说的OO包括OB和OO,是指一种思想,从对象入手的编程方式],首先要模拟的就是其最核心的东西.

 

虽然Ruby,CPP的技巧繁多,但依我现在来看,OO最重要的东西不是多态这些,而是如何去设计一个类,以及如何区别其他类.

 

本质上来说就是类的结构设计,类的构造与析构,如何调用类的成员.

 

对于用C模拟OO来说,类结构自然就是struct,普通成员依旧是普通成员,方法就是函数指针.至于虚函数与否,就是指向的问题了.

 

在目前的OOC-GCC中,通过宏class...eclass来定义一个类,通过ctor...ector和dtor...edtor宏来完成构造和析构.

而调用的时候则要用到new...del宏以及ini...fin宏,如果类在堆上,使用new...del,如果类在栈上,使用ini...fin.

 

至于继承的问题,用struct当然是struct中套struct了,而类型系统以及类型的转换,额外动手写是必须的,不过一种比较好的思路是

 

用union来包含不同的类型,并以一个变量来区分不同的类型,目前还没有弄这一块,因为个人觉得这样做太冗杂了.

 

OO本来就是简化编程的,弄得复杂了就不好了.

 

在最近的尝试中,还试着来模拟foreach这样的行为,但是目前的实现需要他typeof这种类别的关键字的支持[或者__typeof__类似的]

 

下面举一个Iterator的例子,当然这个Iterator和别的语言的必须是有所不同的.

 

假定我们要构造一个描述集合的类B,一个描述元素的类N.

 

要使用我这里的Iterator,只需让B包含一个IterationBase[或用typedef后的IBase],让N包含一个IterationNode[INode]

 

具体的类,以及构造与析构如下

 

//类声明

class(B)
    IBase ibase;
eclass

//构造

ctor(B)
    ini0(IterationBase,&this->ibase);
ector

//析构

dtor(B)
    emptyzs
edtor

//////////////////

//类声明

class(N)
    INode inode;
    //这里v用来保存实际测试用的数据
    int v;
eclass

//构造

ctor(N)
    ini0(IterationNode,&(this->inode));
    this->v=(int)param;
ector

析构

dtor(N)
    emptyzs
edtor

 

下面给出测试用的main函数

int main (int argc, char *argv[])
{
     //声明部分

    Iterator itor;

    ini0(Iterator,&itor);

    N *n1=NULL,*n2=NULL,*n3=NULL,*n4=NULL;

    n1=new(N,(void *)111);

    n2=new(N,(void *)112);

    n3=new(N,(void *)113);

    n4=new(N,(void *)114);

    B *b;

    b=new0(B);


    //插入

    //

    //将n1..n4绑定到b,

    //注意append前两个是不需要next的

    //

    //第一次插入无论用append或prepend

    //都会使base中的指针指向插入的node

    itor.append(&b->ibase,&n1->inode);

    //以后每次的append或prepend都是针对

    //当前base中的cur指针的

    itor.append(&b->ibase,&n2->inode);

    //这里想要在整个base的尾部插入

    //所以后面的每次插入都需要next一下

    itor.next(&b->ibase);

    itor.append(&b->ibase,&n3->inode);

    itor.next(&b->ibase);

    itor.append(&b->ibase,&n4->inode);

    //

    //foreach遍历

    N *np=NULL;

    //哈哈 foreach 遍历 !

    foreach(np,b)

        printf("--%d",np->v);

    eforeach

    printf("\n");

    //反着再遍历一遍 !

    foreach_rev(np,b)

        printf("--%d",np->v);

    eforeach

    //

    //释放堆内存

    del0(N,&n1);

    del0(N,&n2);

    del0(N,&n3);

    del0(N,&n4);

    del0(B,&b);

    return(0);
}

 

正确的输出是

--111--112--113--114
--114--113--112--111

[※最后注明一下,OOC-GCC从名字上就能看出是针对GCC的,用C++的编译器肯定无法编译的

如果是其他纯C的编译器[最好支持C99扩展的],可能需要稍微修改一些,但量不会很大]

 

Lyrics--老男孩片尾曲

Posted on Sat, 13 Nov 2010 13:43:32 -1100

 

老男孩 

演唱:筷子兄弟

 

歌词[中英双语]
  [英文部分基本按照原片中字幕,有几处显而易见的错误已经修改]
  那是我日夜思念深深爱着的人啊
  I am deep in love with her, Thinking of her day and night
  到底我该如何表达
  But how can I express myself
  她会接受我吗
  And will she accept me
  也许永远都不会跟她说出那句话
  Maybe I'll never expose my heart to her
  注定我要浪迹天涯
  For I am always wondering about alone and homeless
  怎么能有牵挂
  How can I be on tenterhooks
  梦想总是遥不可及
  Dreams are but dreams
  是不是应该放弃
  Maybe I should give up
  花开花落又是一季
  Flowers bloom and fade again and again
  春天啊你在哪里
  But where is the spring for me
  青春如同奔流的江河
  Youth like a swift current
  一去不回来不及道别
  rushing by without saying good-bye
  只剩下麻木的我没有了当年的热血
  Leaving me behind numb, cold and spent
  看那漫天飘零的花朵在最美丽的时刻凋谢
  A beautiful flower faded at its prime time in spring
  有谁会记得这世界她来过
  But who cares if it ever lived in this world
  转眼过去多年时间多少离合悲欢
  Many years have elapsed in a brink of the eye
  Witnessing unions and departures joys and sorrows
  曾经志在四方少年羡慕南飞的雁
  The wondering boy envies the wild goose
  That flies to the south before winter comes
  各自奔前程的身影匆匆渐行渐远
  People go in different directions away and gone
  未来在哪里平凡啊谁给我答案
  But where is my future?Just simple ordinary days for me
  Oh,who can give me the answer
  那时陪伴我的人啊你们如今在何方
  Where are you,my friends?
  我曾经爱过的人啊现在是什么模样
  Are you still the same as the ones in my memory?
  当初的愿望实现了吗
  Have you realized your dreams?
  事到如今只好祭奠吗
  Maybe we'll let bygones be bygones
  任岁月风干理想再也找不回真的我
  However hard I may try, I cannot find my true self
  抬头仰望着满天星河
  A million stars are twinkling in the sky
  那时候陪伴我的那颗
  and I try to find out the one used to stay by me
  这里的故事你是否还记得
  Oh, my dear of yesterday,
  do you still remember the time we shared together?
  [solo间奏blablalba]
  生活像一把无情刻刀改变了我们模样
  Life is like a sculptor's graver cold and ruthless
  which has changed our looks
  未曾绽放就要枯萎吗
  Will the flower wither before it ever has a chance to bloom?
  我有过梦想
  But I used to have my dream
  [小重复前面的一段]
  青春如同奔流的江河
  Youth like a swift current
  一去不回来不及道别
  rushing by without saying good-bye
  只剩下麻木的我没有了当年的热血
  Leaving me behind numb, cold and spent
  看那漫天飘零的花朵在最美丽的时刻凋谢
  A beautiful flower faded at its prime time in spring
  有谁会记得这世界她来过
  But who cares if it ever lived in this world
  [小重复前面的一段]
  当初的愿望实现了吗
  Have you realized your dreams?
  事到如今只好祭奠吗
  Maybe we'll let bygones be bygones
  任岁月风干理想再也找不回真的我
  However hard I may try, I cannot find my true self
  抬头仰望着满天星河
  A million stars are twinkling in the sky
  那时候陪伴我的那颗
  and I try to find out the one used to stay by me
  这里的故事你是否还记得
  Oh, my dear of yesterday,
  do you still remember the time we shared together?
  [最后的煽情]
  如果有明天祝福你亲爱的
  If tommorow ever comes, I'll send my best wishes to you,my love.

 

每天一个小程序--Qt结合Designer快速进行快发

Posted on Tue, 02 Nov 2010 09:11:18 -1100

今天写一个小例子,用Qt快发一个简单电话簿

其运行结果如下图

主要需要完成的是一个ListDialog和一个EditDialog

ListDialog的头文件如下

#ifndef LISTDIALOG_H
#define LISTDIALOG_H
#include <QDialog>
#include "EditDialog.h"
#include "ui_listdialog.h"
class ListDialog : public QDialog {
    Q_OBJECT
public:
    ListDialog(); 
private slots:
    void addItem();
    void editItem();
    void deleteItem();
private:
    Ui::ListDialog ui;
};
#endif // LISTDIALOG_H
其cpp文件如下
#include "ListDialog.h"

ListDialog::ListDialog() : QDialog() {
    ui.setupUi( this );
    connect( ui.addButton, SIGNAL(clicked()), this, SLOT(addItem()) );
    connect( ui.editButton, SIGNAL(clicked()), this, SLOT(editItem()) );
    connect( ui.deleteButton, SIGNAL(clicked()), this, SLOT(deleteItem()) );
}

void ListDialog::addItem() {
    EditDialog dlg( this ); 
    if ( dlg.exec() == QDialog::Accepted )
        ui.list->addItem( dlg.name() + " -- " + dlg.number() );

}
void ListDialog::deleteItem() {
    delete ui.list->currentItem();
} 

void ListDialog::editItem() {
    if ( !ui.list->currentItem() )
        return;
    QStringList parts = ui.list->currentItem()->text().split( "--" );
    EditDialog dlg( this );
    dlg.setName( parts[0].trimmed() );
    dlg.setNumber( parts[1].trimmed() );
    if ( dlg.exec() == QDialog::Accepted )
        ui.list->currentItem()->setText( dlg.name() + " -- " + dlg.number() );
}
EditDialog的头文件如下
#ifndef EDITDIALOG_H
#define EDITDIALOG_H
#include "ui_editdialog.h"
#include <QDialog>
class EditDialog : public QDialog {
public:
    EditDialog( QWidget *parent=0 );
    const QString name() const;
    void setName( const QString& );
    const QString number() const;
    void setNumber( const QString& );
private:
    Ui::EditDialog ui;
};
#endif 
其cpp文件如下
#include "EditDialog.h"

EditDialog::EditDialog( QWidget *parent ) : QDialog( parent ) {
    ui.setupUi( this );
}
const QString EditDialog::name() const {
    return ui.nameEdit->text().replace("--","").trimmed();
}
void EditDialog::setName( const QString &name ) {
    ui.nameEdit->setText( name );
}
const QString EditDialog::number() const {
    return ui.numberEdit->text().replace("--","").trimmed();
}
void EditDialog::setNumber( const QString &number ) {
    ui.numberEdit->setText( number );
}
注意,这里面用到了使用Qt Designer生成的布局文件,在运行qmake时,qt会产生特别的makefile
通过该makefile,我们运行make时,还会调用uic来产生ui_xxx头文件,还会调用moc来产生所需的元对象所需的cpp文件
最后列出用Qt生成的Ui文件,保存时保存为*.ui文件即可用Qt Designer打开编辑了
listdialog.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>ListDialog</class>
 <widget class="QDialog" name="ListDialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>401</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Phone Book</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="0">
    <widget class="QListWidget" name="list"/>
   </item>
   <item row="0" column="1">
    <layout class="QVBoxLayout" name="verticalLayout">
     <item>
      <widget class="QPushButton" name="addButton">
       <property name="text">
        <string>Add new</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="editButton">
       <property name="text">
        <string>Edit</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="deleteButton">
       <property name="text">
        <string>Delete</string>
       </property>
      </widget>
     </item>
     <item>
      <spacer name="verticalSpacer">
       <property name="orientation">
        <enum>Qt::Vertical</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>20</width>
         <height>40</height>
        </size>
       </property>
      </spacer>
     </item>
     <item>
      <widget class="QPushButton" name="clearButton">
       <property name="text">
        <string>Clear All</string>
       </property>
      </widget>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>clearButton</sender>
   <signal>clicked()</signal>
   <receiver>list</receiver>
   <slot>clear()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>286</y>
    </hint>
    <hint type="destinationlabel">
     <x>145</x>
     <y>194</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>
editdialog.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>EditDialog</class>
 <widget class="QDialog" name="EditDialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>374</width>
    <height>109</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Editor</string>
  </property>
  <layout class="QGridLayout" name="gridLayout_2">
   <item row="0" column="0">
    <layout class="QGridLayout" name="gridLayout">
     <item row="0" column="0">
      <widget class="QLabel" name="nameLabel">
       <property name="text">
        <string>Name:</string>
       </property>
       <property name="buddy">
        <cstring>nameEdit</cstring>
       </property>
      </widget>
     </item>
     <item row="0" column="1">
      <widget class="QLineEdit" name="nameEdit"/>
     </item>
     <item row="1" column="0">
      <widget class="QLabel" name="numberLabel">
       <property name="text">
        <string>Number:</string>
       </property>
       <property name="buddy">
        <cstring>numberEdit</cstring>
       </property>
      </widget>
     </item>
     <item row="1" column="1">
      <widget class="QLineEdit" name="numberEdit"/>
     </item>
    </layout>
   </item>
   <item row="1" column="0">
    <spacer name="verticalSpacer">
     <property name="orientation">
      <enum>Qt::Vertical</enum>
     </property>
     <property name="sizeHint" stdset="0">
      <size>
       <width>20</width>
       <height>5</height>
      </size>
     </property>
    </spacer>
   </item>
   <item row="2" column="0">
    <widget class="QDialogButtonBox" name="buttonBox">
     <property name="orientation">
      <enum>Qt::Horizontal</enum>
     </property>
     <property name="standardButtons">
      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <tabstops>
  <tabstop>nameEdit</tabstop>
  <tabstop>numberEdit</tabstop>
  <tabstop>buttonBox</tabstop>
 </tabstops>
 <resources/>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>EditDialog</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>227</x>
     <y>91</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>100</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>buttonBox</sender>
   <signal>rejected()</signal>
   <receiver>EditDialog</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>295</x>
     <y>91</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>100</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>
编程方面明天不再更新了,要好好复习考研,虽然说这不是第一次提醒自己了...

每天一个小程序--在python的类和函数中使用静态变量

Posted on Mon, 01 Nov 2010 11:06:43 -1100

在python的类和函数(包括λ方法)中使用静态变量似乎是件不可能[Nothing is impossible]的事,

但总有解决的办法,下面通过实现一个类或函数的累加器来介绍一些较为非主流的方法

方法一 →→ 通过类的__init__和__call__方法

class foo:
    def __init__(self, n=0):
        self.n = n
    def __call__(self, i):
        self.n += i
        return self.n
    
a=foo()
print a(1)
print a(2)
print a(3)
print a(4)

方法二 →→ 在函数中定义一个类

def foo2 (n=0):
    class acc:
        def __init__ (self, s):
            self.s = s
        def inc (self, i):
            self.s += i
            return self.s
    return acc (n).inc
    
a=foo2()
print a(1)
print a(2)
print a(3)
print a(4)

方法三 →→ 使用堆上的匿名参数

def foo3 (i, L=[]):
    if len(L)==0:
        L.append(0)
    L[0]+=i
    return L[0]

print foo3(1)
print foo3(2)
print foo3(3)
print foo3(4)

在python官方的2.6环境下运行,
上述三段代码得到的结果都是

1
3
6
10

每天一个小程序--python编译pyc文件

Posted on Mon, 01 Nov 2010 11:05:47 -1100

今天开始写这个,希望能坚持下去,不过真忙了也没办法,

今天记录下如何编译python的方法

比如有下面简单的一个程序

def show():
    print 'hello world!'
if __name__ == '__main__':
    show()

 

如果想编译它,可以用py_compile这个包,

下面修改一下

import   py_compile;     
py_compile.compile('test01.py')

def show():
    print 'hello world!'
if __name__ == '__main__':
    show()

这时再运行下,除了输出"你好世界"以外,还会生成对应的*.pyc文件

当然也可以不改动程序,直接运行这个命令

python -mpy_compile test01.py
##假定文件命名为test01.py
-m是直接运行某个包

1020考研总结

Posted on Wed, 20 Oct 2010 13:16:29 -1100

模电数电1020

§微变等效电路求解
§工作点稳定电路参量的计算
§差分放大电路
§数值转换,逻辑转换

  • ●不管什么,先把等效电路画出来,直流+交流
  • ●最大不失真输出电压
    UCQ与UCC和UCES[有时按0→GND估算]之差的绝对值
    如果问的是幅度则不需要除以√2,否则要除一下
  • ●常见的稳定电路要引入负反馈
    比如增加射极电阻,以及在基集间增加电阻
  • ●通过射极电阻引入负反馈若不加旁路电容,可以使电压放大倍数与β无关(-RL'/RE),但放大倍数较有旁路电容时大大缩小
  • ●抑制温度漂移的方法
    • 引入直流负反馈
    • 采用温度补偿的方法,利用热敏元件[比如热敏电阻和二极管<2.4.5>]抵消放大管的变化
    • 采用特性相同的管子,构成"差分放大电路"
  • ●单管共射频率参数,相位中频-180°,低频-90°,高频-270°
  • 负数:原码→除符号位取反→反码→+1→补码
  • 10进制小数化为二进制时用乘二取一并去一的方法[总结的不好,凑合着记忆了]
  • 与或→与非--与非:X→(X')'
  • 与或→与或非:Y+Y'=1,卡诺图0的反
  • 与或→或非-或非:先化成与或非,再X→(X')'  

下面测试下用ScribeFire插图,貌似没法更改投稿选项,这个不应投的啊....

http://mblogpic.store.qq.com/mblogpic/56a76b98890049f95506/2000

 

test ScribeFire

Posted on Tue, 19 Oct 2010 08:23:24 -1100

test ScribeFire

恶心的GObject[Part I][v0.1]

Posted on Sat, 18 Sep 2010 05:43:43 -1100

虽然GObject最初是为了简化C语言的OO开发而设立的,但毕竟C不是天生的OO语言,而其中有太多抽象的东西,反而让其难以入门.....

虽然以前花了很长时间去研究这东西,但限于当时的水平,一些东西并没有弄透彻,甚至有不少错误....

因为前段自己尝试用C语言来模拟OO,积累了不少经验,最近偶然又回顾了下GObject,一些似懂非懂的概念明朗了许多.....

Part I. GObject中最恶心的概念

下面罗列几个概念,都是难以弄明白的....

GCClosure,GClosure,GClosureMarshal,

GClosureNotifyData,GClosureNotify,SignalAccumulator,GSignalAccumulator...

晕了吧,估计不少学了一段Gtk的人对上面的概念还是一知半解...

在具体展开前,我们需要知道GObject是怎么描述类,以及如何进行类型的判定和转换的....

我们知道C语言进行OO编程的时候要大量用到结构体函数指针,GObject也不例外,

而GObject中每一个类也是一到多个结构体[多个结构体是干嘛的后面会解释],GObject本身用多个int型变量来表示各个类型,类型的检测就是一个int型变量的检查,而类型的转换也是根据这个int型的变量[需要判断是否可以转换],进行结构体或指针的强制转换.

GCClosure,GClosure就是两个结构体!

前面的GCClosure多了个C,自然是C语言用的,不难想到GCClosure是GClosure一个封装,提供针对C语言的一种绑定,自然,GObject可以绑定到多种语言,比如Python,Ruby等等,目前绑定的比较好的是C[原生]/CPP/VALA/PYTHON

仔细看下

struct _GCClosure
{
  GClosure	closure;
  gpointer	callback;
};

 

注意,_GCClosure会用typedef在定义成GCClosure,这一点后面都类似,以后不再特殊说明,

通过GCClosure定义,不难发现其封装了一个GClosure的同时,还有一个callback,猜到了吧!GCClosure的主要功能就是回调!

估计不够淡定的朋友会觉得这也太扯淡了,回调的本质就是一个函数指针,包装这么多层干嘛?GObject这样设计自然有它的道理,

我们知道不同语言有不同的类型,比如C语言里就没有原生的String,

而即便是C语言我们仅在C语言,我们在定义回调函数时也可能要用到不同的形式,比如有的返回int,有的返回void,我们怎么区别这些呢?

不急,待我一步一步分析,

GOBject中GClosureMarshal是一个函数指针,但是要注意它是用来定义回调函数类型的而不是直接调用的!

typedef void  (*GClosureMarshal)	(GClosure	*closure,
					 GValue         *return_value,
					 guint           n_param_values,
					 const GValue   *param_values,
					 gpointer        invocation_hint,
					 gpointer	 marshal_data);

 

看到它的参数没有,指定了回调返回值类型,回调函数参数的个数等等

而每一个GClosure都要有一个绑定的GClosureMarshal,

具体来看看

struct _GClosure
{
  /*< private >*/
  volatile      	guint	 ref_count : 15;
  volatile       	guint	 meta_marshal : 1;
  volatile       	guint	 n_guards : 1;
  volatile       	guint	 n_fnotifiers : 2;	/* finalization notifiers */
  volatile       	guint	 n_inotifiers : 8;	/* invalidation notifiers */
  volatile       	guint	 in_inotify : 1;
  volatile       	guint	 floating : 1;
  /*< protected >*/
  volatile         	guint	 derivative_flag : 1;
  /*< public >*/
  volatile       	guint	 in_marshal : 1;
  volatile       	guint	 is_invalid : 1;

  /*< private >*/	void   (*marshal)  (GClosure       *closure,
					    GValue /*out*/ *return_value,
					    guint           n_param_values,
					    const GValue   *param_values,
					    gpointer        invocation_hint,
					    gpointer	    marshal_data);
  /*< protected >*/	gpointer data;

  /*< private >*/	GClosureNotifyData *notifiers;

};

 

注意,官方网上的Manual可能描述上过老,容易误导初学者,上面的源自GOjbect源码

罗列上面代码并不是大家一个一个分析的,只是要大家知道前面我说的一个Closure绑定一个Marshaller.....

我前面说过GClosureMarshal是用来定义回调函数类型的,不是用来调用的,GObject中真正的回调是marshal_data[够抽象的,这个是一个void *指针] ,关于这个我不多说什么[因为自己也没时间研究],因为一般不常用,主要用于其它语言间的绑定.

对于C语言,GObject本身已经提供了很多现成的C语言专用的Marshaller,下面给出一个最简单的C专用的Marshaller

/* VOID:VOID (./gmarshal.list:26) */
void
g_cclosure_marshal_VOID__VOID (GClosure     *closure,
                               GValue       *return_value G_GNUC_UNUSED,
                               guint         n_param_values,
                               const GValue *param_values,
                               gpointer      invocation_hint G_GNUC_UNUSED,
                               gpointer      marshal_data)
{
  typedef void (*GMarshalFunc_VOID__VOID) (gpointer     data1,
                                           gpointer     data2);
  register GMarshalFunc_VOID__VOID callback;
  register GCClosure *cc = (GCClosure*) closure;
  register gpointer data1, data2;

  g_return_if_fail (n_param_values == 1);

  if (G_CCLOSURE_SWAP_DATA (closure))
    {
      data1 = closure->data;
      data2 = g_value_peek_pointer (param_values + 0);
    }
  else
    {
      data1 = g_value_peek_pointer (param_values + 0);
      data2 = closure->data;
    }
  callback = (GMarshalFunc_VOID__VOID) (marshal_data ? marshal_data : cc->callback);

  callback (data1,
            data2);
}

看到了吧那个callback可以指向marshal_data,而marshal_data也是一个函数指针,一般来说它应指向GCClosure中的callback,只是真正调用时是从GClosure中来调用而已.

而原始的GClosureMarshal本质上也是这样的......

注意VOID_VOID表示回调返回VOID,额外的参数为VOID[就是没有额外的参数]

 

好了,分析的差不多了,有了上面的基础我们就不难理解signal的链接与回调

对于C语言,

一个SIGNAL在CONNECT时,实际创建了一个C语言的Closure,并绑定了一个C语言的Marshaller,而C语言Marshaller的类型,要在SIGNAL 创建时来定义[注意常见的Gtk中g_signal_connect的常见SIGNAL都是已经定义好回调的类型的,所以你在定义已知信号的回调是要按类型定义],回调函数是在GCClosure中定义的,但本质上是通过GClosure来调用....

简单表示下

GCClosure{
  GClosure {
      ...
     其它很多和类型相关的东西; 
      ...
      GClosureMarshal marshal; //这是个函数指针,
      //这个的参数中有一个要指向下面定义的callback
     ...
  }
 void *callback;
}

而我们在ui使用回调是将SIGNAL发送[EMIT]出去,若在signal队列中有绑定的HANDLER[就是我们的callback],就由其处理...

signal的发送非常复杂,这里不再赘述[如果要研究这个,可以从SignalNode结构入手].....

我们仅需要知道[对于C语言]一旦找到了相应的SIGNAL的ID,就会找到指定GClosure[不是GCClosure],然后通过其找到GClosure并调用其中的marshall函数[传入的参数有何callback相关的],进而调用回调函数.

如果是C语言,可以调用类似g_cclosure_marshal_VOID__VOID的一个定义好的marshal,其内部会调用对应的指向callback的函数[具体参考上面那个C语言VOID_VOID型marshal,调用了传入marshal_data函数指针,也就是我们绑定到GCClosure的callback指针]

好了最扯淡的部分结束了,还有四个[GClosureNotifyData , GClosureNotify , SignalAccumulator , GSignalAccumulator]没说,不过这四个比较简单,理解起来也容易些,下面为了节约时间,一并说了.

GClosureNotifyData 是一个结构体,它包含了一个函数指针GClosureNotify

SignalAccumulator 也是一个结构体,他也包含了一个函数指针GSignalAccumulator

具体代码

struct _GClosureNotifyData
{
  gpointer       data;
  GClosureNotify notify;
};

typedef void  (*GClosureNotify)     (gpointer    data,
                     GClosure   *closure);

typedef struct
{
  GSignalAccumulator func;
  gpointer           data;
} SignalAccumulator;

typedef gboolean (*GSignalAccumulator)  (GSignalInvocationHint *ihint,
                     GValue            *return_accu,
                     const GValue          *handler_return,
                     gpointer               data);

上面的data即回调函数传入的参数

如果我们回调的参数中有定义在堆上的,并且调用完要释放,那么应该通过绑定一个GClosureNotify型的指针,而GSignalAccumulator指针则是用来控制某个信号响应后是否继续向下传递用的.

注意: GClosure中有指向GClosureNotifyData的指针,而SignalNode结构体中有个指向SignalAccumulator结构体的指针.

 

好了,本篇就到此为止,基本分析了GObject中最难理解的概念,因为写的仓促和个人水平有限希望发现问题的朋友能够给予指正.

我的邮件地址 pingf0@gmail.com

OOC-Embeded_C语言模拟对象的应用

Posted on Sun, 05 Sep 2010 01:21:10 -1100

其实还是在折腾如何用C语言模拟对象的机制,

现在这个版本个人该觉还是不错的,可以用GCC以及KEIL,IAR等附带的编译器来编译

另外还在此基础上实现了常用的数据结构,包括下面这些,

链表[包括单链表,双链表,循环链表],堆栈,队列,集合,

哈希表[包括链式和开放地址式],二差树[普通二叉树,平衡二叉树],

堆/优先队列,图......

项目地址:

http://code.google.com/p/ooc-embeded/

提供win下编译好的DLL,源代码可通过SVN获取

核心代码如下,

/**
 * OOC-Embeded 
 * version : see the log file
 * status  : beta 
 * author  : Jesse Meng 
 * Blog    : http://www.pingf.me 
 * E-mail  : pingf0@gmail.com
 */
#ifndef __JC_OOP__
#define __JC_OOP__
#include <stdio.h>
#include <stdlib.h>
//
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#elif   defined BUILD_WITH_DLL  
/* EXE import */
#define EXPORT __declspec(dllimport)
#else
#define EXPORT
#endif
//
#define USE_HEAP_FOR_CLASS
//
#ifdef USE_CALLOC_FOR_CLASS
#define _CLASS_ALLOC(this,Type) \
this=(struct _##Type *)malloc(sizeof(struct _##Type));  
#else
#define _CLASS_ALLOC(this,Type) \
this=(struct _##Type *)calloc(1,sizeof(struct _##Type));  
#endif 
/////////////////////////////////////////////////////////////
#ifdef USE_HEAP_FOR_CLASS
#define _CLASS(Type) \
typedef struct _##Type Type; \
EXPORT int init##Type(struct _##Type * this,void *param); \
EXPORT int fin##Type(struct _##Type *this,void *param); \
EXPORT struct _##Type * new##Type(void *param); \
EXPORT int del##Type(struct _##Type **this,void *param); \
struct _##Type \
{
//////////////////////////////////////
#define _CTOR(Type) \
EXPORT struct _##Type * new##Type(void *param) \
{ \
	struct _##Type *this; \
	int initRet=0; \
	_CLASS_ALLOC(this,Type); \
	if( NULL==this ) { \
        return NULL; \
    } \
	initRet=init##Type(this,param); \
	if(-1==initRet) { \
        free(this); \
        return NULL; \
    } \
	return this; \
} \
EXPORT int init##Type(struct _##Type * this,void *param) \
{  
//
#define _DTOR(Type) \
EXPORT int del##Type(struct _##Type **this,void *param) \
{ \
	int finRet=0; \
	if(NULL==(this)) { \
        return -1; \
    } \
	finRet=fin##Type(*(this),param); \
	if(-1==finRet) {\
        return -1; \
    } \
	free(*(this)); \
	(*(this))=NULL; \
	return 0; \
} \
EXPORT int fin##Type(struct _##Type *this,void *param) \
{ 
//
#else
#define _CLASS(Type) \
typedef struct _##Type Type; \
EXPORT int init##Type(struct _##Type * this,void *param); \
EXPORT int fin##Type(struct _##Type *this,void *param); \
struct _##Type \
{
//////////////////////////////////////
#define _CTOR(Type) \
EXPORT int init##Type(struct _##Type * this,void *param) \
{  
//
#define _DTOR(Type) \
EXPORT int fin##Type(struct _##Type *this,void *param) \
{ 
//  
#endif 
/////////////////////
#define _END_CLASS };
//
#define _END_CTOR \
	return  0; \
} 
// 
#define _END_DTOR \
return 0; \
}
//
#define _HAVES(Type,name) \
static struct _##Type##S s; \
//
#define _AUTOS(Type,name,sparam) \
do{ \
    init##Type##S(&s,sparam); \
    this->name=&s; \
}while(0);
//
#define _HAVEP(Type) \
static struct _##Type##P *p=NULL; 
//
#define _CASTP(Type) \
do{ \
    p=(struct _##Type##P *)param; \
}while(0);
/////////////////////////////////////////////////////////////
#define CLASS(Type) _CLASS(Type)
#define END_CLASS _END_CLASS 
//
#define CTOR(Type) _CTOR(Type)
#define END_CTOR _END_CTOR
//
#define DTOR(Type) _DTOR(Type)
#define END_DTOR _END_DTOR
//
#define HAVES(Type,name) _HAVES(Type,name)  
//
#define AUTOS(Type,name,sparam) _AUTOS(Type,name,sparam)  
//
#define HAVEP(Type) _HAVEP(Type)  
//
#define CASTP(Type) _CASTP(Type)  
//
#endif


C语言模拟OO机制的再研究

Posted on Fri, 27 Aug 2010 06:00:38 -1100

因为过一段日子可能又要写些单片机上的代码,所以难免还是离不开C.

以前研究过GObject,也自己用宏写过一些模拟OO的东西,不过这些用在单片机上就不那么顺了.....

于是就想把OO的思想进一步简化,

最和新的东西无非就是类的声明(设计),构造与析构,

所以浓缩了下面的代码,并保证在Keil这类工具上0警告编译通过....

/**
 * OOC-Embeded [Jcoop elite version]
 * version : 0.2.0827elite
 * status  : beta 
 * author  : Jesse Meng 
 * Blog    : http://www.pingf.me 
 * E-mail  : pingf0@gmail.com 
 */


#ifndef __JC_OOP__
#define __JC_OOP__
#include <stdio.h>
#include <stdlib.h>
 
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#elif   defined BUILD_WITH_DLL  
/* EXE import */
#define EXPORT __declspec(dllimport)
#else
#define EXPORT
#endif

#define USE_HEAP_FOR_CLASS
 
#ifdef USE_CALLOC_FOR_CLASS
#define _CLASS_ALLOC(this,Type) \
this=(struct _##Type *)malloc(sizeof(struct _##Type));  
#else
#define _CLASS_ALLOC(this,Type) \
this=(struct _##Type *)calloc(1,sizeof(struct _##Type));  
#endif 

/////////////////////////////////////////////////////////////
#ifdef USE_HEAP_FOR_CLASS
#define _CLASS(Type) \
typedef struct _##Type Type; \
EXPORT int init##Type(struct _##Type * z); \
EXPORT int fin##Type(struct _##Type *z); \
EXPORT struct _##Type * new##Type(void); \
EXPORT int del##Type(struct _##Type **z); \
struct _##Type \
{
//
#define _END_CLASS };
//////////////////////////////////////
#define _CTOR(Type) \
EXPORT struct _##Type * new##Type(void) \
{ \
	struct _##Type *this; \
	int initRet=0; \
	_CLASS_ALLOC(this,Type); \
	if( NULL==this ) { \
        return NULL; \
    } \
	initRet=init##Type(this); \
	if(initRet<0) { \
        return NULL; \
    } \
	return this; \
} \
EXPORT int init##Type(struct _##Type * z) \
{  \
	struct _##Type * this=NULL;\
	this=(struct _##Type *)z; \
	if( NULL==this ) { \
        return -1; \
    }  
        
//
#define _END_CTOR \
	return  1; \
} 
//
#define _DTOR(Type) \
EXPORT int del##Type(struct _##Type **z) \
{ \
	struct _##Type **this = NULL; \
	int finRet=0; \
	this=(struct _##Type **)z;  \
	if(NULL==this) { \
        return -1; \
    } \
	finRet=fin##Type(*this); \
	if(finRet<0) {\
        return -1; \
    } \
	free(*this); \
	(*this)=NULL; \
	return 1; \
} \
EXPORT int fin##Type(struct _##Type *z) \
{ \
	struct _##Type * this=NULL; \
	this=(struct _##Type *)z; \
	if( NULL==this ) { \
        return -1; \
    } 
//  
#define _END_DTOR \
return 1; \
}
#else
#define _CLASS(Type) \
typedef struct _##Type Type; \
EXPORT int init##Type(struct _##Type * z); \
EXPORT int fin##Type(struct _##Type *z); \
struct _##Type \
{
//
#define _END_CLASS };
//////////////////////////////////////
#define _CTOR(Type) \
EXPORT int init##Type(struct _##Type * z) \
{  \
	struct _##Type * this=NULL;\
	this=(struct _##Type *)z; \
	if( NULL==this ) { \
        return -1; \
    }  
        
//
#define _END_CTOR \
	return  1; \
} 
//
#define _DTOR(Type) \
EXPORT int fin##Type(struct _##Type *z) \
{ \
	struct _##Type * this=NULL; \
	this=(struct _##Type *)z; \
	if( NULL==this ) { \
        return -1; \
    } 
//  
#define _END_DTOR \
return 1; \
}
#endif 
 
/////////////////////////////////////////////////////////////
#define CLASS(Type) _CLASS(Type)
#define END_CLASS _END_CLASS 
//
#define CTOR(Type) _CTOR(Type)
#define END_CTOR _END_CTOR
//
#define DTOR(Type) _DTOR(Type)
#define END_DTOR _END_DTOR
//
#endif

因为定义的东西少[也就100多行吧],所以使用起来就容易,省去了很多要记忆的东西,

下面是用例测试

#include <stdio.h>
#include "jc_oop.h"


CLASS(Test)
    int a;
    int b;
END_CLASS

CTOR(Test)
    printf("Test constructor");
    //this->a=1;
    //this->b=2;
END_CTOR
//
DTOR(Test)
    printf("Test destructor");
    this->a=this->b=0;
END_DTOR

int main (int argc, char *argv[])
{
    Test stk;
    Test * heap=NULL;
    heap=newTest();
    delTest(&heap);
    initTest(&stk);
    finTest(&stk);
    return(0);
}

别看这么简单,但是像继承和组合的关系还是可以表示清楚的

比如下面测试了组合关系

 

#include <stdio.h>
#include "jc_oop.h"


CLASS(Test)
    int a;
    int b;
END_CLASS

CTOR(Test)
    printf("Test constructor\n");
    //this->a=1;
    //this->b=2;
END_CTOR
//
DTOR(Test)
    printf("Test destructor\n");
    this->a=this->b=0;
END_DTOR

CLASS(Test2)
    Test *test;
END_CLASS

CTOR(Test2)
    printf("Test2 constructor\n");
    this->test=newTest();
END_CTOR
//
DTOR(Test2)
    printf("Test2 destructor,actually this is after Test\n");
    delTest(&(this->test));
END_DTOR

int main (int argc, char *argv[])
{
    Test stk;
    Test2 * heap=NULL;
    heap=newTest2();
    delTest2(&heap);
    return(0);
}

至于像方法之类的东西,自然还是用函数指针来模拟,

为了在嵌入式系统上使用方便,不再用宏来定义