Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用C、gcc、C99和宏优化微控制器的最低限度OOP 通常我必须在C中编写微控制器,因为C++编译器经常不可用,或者由于各种错误不能生成非常小的代码。但通常,OOP“语法糖”在使硬件程序更清晰地封装以便于维护时非常方便;因此,我想知道是否有一种方法可以在C中使用OOP语法,在这种方法中,可以尽可能多地利用OOP开销(在不需要时)以可移植的方式进行优化。例如:如果gcc不适用于不同的微控制器,那么可以针对不同的微控制器使用gcc进行优化,或者使用gcc的预处理器和通用ANSI-C编译器进行优化_C_Oop_Pointers_Gcc - Fatal编程技术网

使用C、gcc、C99和宏优化微控制器的最低限度OOP 通常我必须在C中编写微控制器,因为C++编译器经常不可用,或者由于各种错误不能生成非常小的代码。但通常,OOP“语法糖”在使硬件程序更清晰地封装以便于维护时非常方便;因此,我想知道是否有一种方法可以在C中使用OOP语法,在这种方法中,可以尽可能多地利用OOP开销(在不需要时)以可移植的方式进行优化。例如:如果gcc不适用于不同的微控制器,那么可以针对不同的微控制器使用gcc进行优化,或者使用gcc的预处理器和通用ANSI-C编译器进行优化

使用C、gcc、C99和宏优化微控制器的最低限度OOP 通常我必须在C中编写微控制器,因为C++编译器经常不可用,或者由于各种错误不能生成非常小的代码。但通常,OOP“语法糖”在使硬件程序更清晰地封装以便于维护时非常方便;因此,我想知道是否有一种方法可以在C中使用OOP语法,在这种方法中,可以尽可能多地利用OOP开销(在不需要时)以可移植的方式进行优化。例如:如果gcc不适用于不同的微控制器,那么可以针对不同的微控制器使用gcc进行优化,或者使用gcc的预处理器和通用ANSI-C编译器进行优化,c,oop,pointers,gcc,C,Oop,Pointers,Gcc,我发现只有这样的线程,它们通常通过在结构中嵌入指针来执行OOP,但这并不总是我想要的,因为当我对虚拟方法或类似的东西不感兴趣时,它会浪费内存。我可以在需要这些特性的链接中始终遵循编码风格,但我想开发不需要这些特性的技术;例如,我只想用OOP范式编程,用简单易懂的代码(不一定是C++,虽然我喜欢C++),并且当一些OOP范式不使用时,仍然能够实现最小的C程序内存使用。 因此,我尝试使用gcc和C99,因为一般来说,gcc 3.2或更高版本适用于大多数平台;并意识到我可以使用C99中的sizeof(

我发现只有这样的线程,它们通常通过在结构中嵌入指针来执行OOP,但这并不总是我想要的,因为当我对虚拟方法或类似的东西不感兴趣时,它会浪费内存。我可以在需要这些特性的链接中始终遵循编码风格,但我想开发不需要这些特性的技术;例如,我只想用OOP范式编程,用简单易懂的代码(不一定是C++,虽然我喜欢C++),并且当一些OOP范式不使用时,仍然能够实现最小的C程序内存使用。 因此,我尝试使用gcc和C99,因为一般来说,gcc 3.2或更高版本适用于大多数平台;并意识到我可以使用C99中的sizeof()和typeof()编译器函数从未使用/未初始化的联合成员(因此类必须是具有子结构的联合)自动索引类(这是一种“技巧”),以便访问宏创建的编译时常量查找表,该表可以绑定数据和方法,并保证所有类型的检查。等等等等等等

例如:GCC允许对常量结构和数组进行优化,当它们的成员仅作为常量表达式访问时,所以我想我可以使用它来构建一个基于宏的编译时绑定系统,其中OOP开销在GCC中处理,并实际优化出最终的二进制

有了这个系统,我现在可以进行可变的宏方法调用,比如:M(a,init,“With”,“any”,“parameters”,7),它使用可变数量的参数查找变量a的类型,调用method init

请参阅下面的代码示例,并尝试使用它们——这比解释更简单:使用gcc-E查看宏扩展,注意对于仅限于ANSI的编译器,typeof()运算符必须替换为(void*)类型转换;类型检查仅适用于GCC

代码可以剪切和粘贴到文本编辑器中,文件名在第一行,它可以在普通PC系统上编译和运行

虽然我成功地消除了每个结构中的单个指针,以“指向”类的方法列表,从而在内存有限的微控制器中节省了内存,但我还是不太明白如何让编译器优化未使用的方法指针,因为我不得不使用(void*)类在数组中保存它们的指针,这些指针需要内存地址(结构的地址)和链接器实例;不要优化了

因此:我想知道是否有人知道一种改进我的解决方案的方法,即制作某种初始化的方法结构,在编译后进行优化(没有链接器地址),例如:当它的成员在代码中仅作为常量表达式访问时。本质上,我需要能够在数组中查找一个元素,其中每个数组元素的初始化部分是不同的classXXX\u mt,而不是classXXX\u mt所有类型转换为(void*)的地址列表

如果有人能想出一个简单的解决方案,我还想得到另外两个改进;cpp(c预处理器)不允许通过令牌连接从以前的宏中定义新宏(据我所知),因此我必须创建固定长度的宏列表(在我的示例中最多10个)来保存类定义;这意味着我在一个项目中最多只能上10节课;但理想情况下,我希望有一种方法使我的代码更通用,这样cpp就可以动态创建可变长度的列表。问题与c预处理器无法自动“计数”有关

其次,当我尝试为较新版本的GCC使用匿名结构时,我可能会通过从类联合定义中删除“m”名称并使用GCC-std=c11编译,从而消除访问ISO-C中成员数据所需的额外“m”,例如:foo.m.mydata,然后它只会给我错误,声称该结构未定义任何内容。。。因此,联合体内部的匿名结构即使在GCC4.8中也不起作用,尽管它应该起作用;如何使匿名结构正常工作

下面是我如何测试和实现一个包含文件voidbind.h的示例,该文件构建一个类列表,并将方法静态链接到该类类型的变量

最终,系统允许我像这个例子一样编程;我用gcc 4.0到4.9编译了它,没有问题:

//classtest.c
#ifndef MACROCHECK  // Don't macro expand stdio.h, it's ugly...
#include <stdio.h>  // to see macros, do gcc -D MACROCHECK -E classtest.c
#endif
#include "class1.h" // include example class, library.

#define _VOID_FINALIZE
#include "voidbind.h" // Make class list finalized, no more classes allowed

void main( void ) {
    class1_ct a; // types ending in _ct are the macro created class types
    class2_ct b;

    M( a , init ); // Call method of variable, a, and the function init.
    printf("a=%s %s\n",a.m.name, M( b, tryme, "echo is this" ) ); 
    // I'd love to be rid of .m. in the previous line using anonymous struct
}

一般来说,你要的是C++。你所发表的例子最有可能是使用C++编译器的效率更高或效率更高。

经常在嵌入式目标上有很多过时的版本,代码< > GCC < /C> >为C++生成坏代码,或者不支持所有的GRO C++细节。 您可以尝试运行<代码> ${YuyAcgRyPrime}-g++-NoSTDLIB——NOSTDICN< /COD>,这将使解析器中的C++语法不浪费所有空间。如果要禁用其他功能,可以使用remove runtime type checking and exception support添加

-fno rtti-fno exceptions
(请参阅)

<>因为C++分析器是C前端的一部分,即使C++没有被你的微控制器供应商官方支持,这仍然可能有效。
//class1.h
#ifndef _class1_h
#define _class1_h


// Define the data type structure for class1
typedef struct {
    char* name;
    int   one;
} class1_t;

// Define the method type structure for class1 
union class1_ctt ; // class type tag, incomplete tag type for class1_ct
typedef struct { // method prototypes
    void (*init)( union class1_ctt* ); // passed a pointer to class1_ct
} class1_mt;

// bind class1_mt and class1_t together into class1_ct
#define _VOID_NEW_CLASS class1
#include "voidbind.h"

// Begin class2 definition
typedef struct { // define data type for class2
    int x;
} class2_t;

union class2_ctt ; // class type tag, forward definition
typedef struct { // method prototypes for class2
    char* (*tryme)( union class2_ctt*, char* echo );
} class2_mt;

// bind class2_t and class2_mt together into class2_ct
#define _VOID_NEW_CLASS class2
#include "voidbind.h"

// --------------------------------------------- Start library code
// This would normally be a separate file, and linked in
// but as were doing a test, this is in the header instead...

//#include <class1.h>

void class1_init( class1_ct* self ) {
    self->m.name = "test";
    self->m.one=5;  
}

// Define class1's method type (_mt) instance of linker data (_ld):
// voidbind.h when it creates classes, expects an instance of the
// method type (_mt) named with _mt_ld appended to link the prototyped
// methods to C functions.  This is the actual "binding" information
// and is the data that I can't get to "optimize out", eg: when there
// is more than one method, and some of them are not used by the program

class1_mt class1_mt_ld = {
    .init=class1_init
};

// ----------- CLASS2 libcode ----

char* class2_tryme( class2_ct* self, char* echo ) {
    return echo;
}

// class2's method type (_mt) instance of linker data (_ld).
class2_mt class2_mt_ld = { // linker information for method addresses
    .tryme=class2_tryme
};

// --------------------------------------------- End of library code

#endif
// voidbind.h
// A way to build compile time void pointer arrays
// These arrays are lists of constants that are only important at compile
// time and which "go away" once the compilation is finished (eg:static bind).
// Example code written by: Andrew F. Robinson of Scappoose


#ifdef _VOID_WAS_FINALIZED //#{
#error voidbind_h was included twice after a _VOID_FINALIZE was defined
#endif //#}

// _VOID_FINALIZE, define only after all class headers have been included. 
// It will simplify the macro expansion output, and minimize the memory impact
// of an optimization failure or disabling of the optimization in a bad compiler
// in hopes of making the program still work.

#ifdef _VOID_FINALIZE //#{
#define _VOID_WAS_FINALIZED
#undef _VOID_BIND
static inline void* _VOID_BIND( int x ) {
    return _VOID_BIND_OBJ[ x ];
}
#else

// Make sure this file has data predefined for binding before being
// included, or else error out so the user knows it's missing a define.

#if ! defined( _VOID_NEW_OBJ ) && ! defined( _VOID_NEW_CLASS ) //#{
#error missing a define of _VOID_NEW_OBJ or _VOID_NEW_CLASS
#endif //#}


// Initialize a macro (once) to count the number of times this file
// has been included; eg: since one object is to be added to the void
// list each time this file is #included. ( _VOID_OBJn ) 

#ifndef _VOID_OBJn //#{
#define _VOID_OBJn _ERROR_VOID_OBJn_NOT_INITIALIZED_

// Initialize, once, macros to do name concatenations 
#define __VOID_CAT( x, y ) x ## y
#define _VOID_CAT( x, y ) __VOID_CAT( x , y )

// Initialize, once, the empty void* list of pointers for classes, objs.
#define _VOID_BIND_OBJ (void* []){\
    _VOID_OBJ0() , _VOID_OBJ1() , _VOID_OBJ2() , _VOID_OBJ3() , _VOID_OBJ4()\
 ,  _VOID_OBJ5() , _VOID_OBJ6() , _VOID_OBJ7() , _VOID_OBJ8() , _VOID_OBJ9()\
}
// Define a function macro to return the list, so it can be easily
// replaced by a _FINALIZED  inline() function, later
#define _VOID_BIND(x) _VOID_BIND_OBJ[ x ]

// All void pointers are initially null macros.  So the void list is 0.
#define _VOID_OBJ0()  0
#define _VOID_OBJ1()  0
#define _VOID_OBJ2()  0
#define _VOID_OBJ3()  0
#define _VOID_OBJ4()  0
#define _VOID_OBJ5()  0
#define _VOID_OBJ6()  0
#define _VOID_OBJ7()  0
#define _VOID_OBJ8()  0
#define _VOID_OBJ9()  0
#endif //#}

// Figure out how many times this macro has been called, by
// checking for how many _VOID_OBJn() function macros have been
// replaced by inline functions

#undef _VOID_OBJn

#if defined( _VOID_OBJ0 ) // #{
#undef _VOID_OBJ0
#define _VOID_OBJn 0
#elif defined( _VOID_OBJ1 )
#undef _VOID_OBJ1
#define _VOID_OBJn 1
#elif defined( _VOID_OBJ2 )
#undef _VOID_OBJ2
#define _VOID_OBJn 2
#elif defined( _VOID_OBJ3 )
#undef _VOID_OBJ3
#define _VOID_OBJn 3
#elif defined( _VOID_OBJ4 )
#undef _VOID_OBJ4
#define _VOID_OBJn 4
#elif defined( _VOID_OBJ5 )
#undef _VOID_OBJ5
#define _VOID_OBJn 5
#elif defined( _VOID_OBJ6 )
#undef _VOID_OBJ6
#define _VOID_OBJn 6
#elif defined( _VOID_OBJ7 )
#undef _VOID_OBJ7
#define _VOID_OBJn 7
#elif defined( _VOID_OBJ8 )
#undef _VOID_OBJ8
#define _VOID_OBJn 8
#elif defined( _VOID_OBJ9 )
#undef _VOID_OBJ9
#define _VOID_OBJn 9 
#else
#error Attempted to define more than ten objects
#endif //#}

// -------------------------------------------------------
// If the user defines _VOID_NEW_CLASS
// Create a union of the two class structs, xxx_t and xxx_mt
// and call it xxx_ct.  It must also be compatible with xxx_ctt, the tag
// which allows forward definitions in the class headers.

#ifdef  _VOID_NEW_CLASS //#{
#ifndef M  //#{
#define M( var , method , ... )\
        (( (typeof(var._VOIDBIND_T))_VOID_BIND( sizeof(*(var._VOIDBIND)) ) )->\
        method( & var , ## __VA_ARGS__ ))
#endif //#}
extern _VOID_CAT( _VOID_NEW_CLASS , _mt ) _VOID_CAT( _VOID_NEW_CLASS , _mt_ld );
typedef union _VOID_CAT( _VOID_NEW_CLASS, _ctt ) {
    char (*_VOIDBIND)[ _VOID_OBJn ];
    _VOID_CAT( _VOID_NEW_CLASS , _mt ) *_VOIDBIND_T;
    _VOID_CAT( _VOID_NEW_CLASS , _t ) m ;
} _VOID_CAT( _VOID_NEW_CLASS , _ct );

static inline void* (_VOID_CAT( _VOID_OBJ , _VOID_OBJn )) ( void ) {
    return & _VOID_CAT( _VOID_NEW_CLASS, _mt_ld );
}
#undef _VOID_NEW_CLASS
#else // ---------- Otherwise, just bind whatever object was passed in
static inline _VOID_CAT( _VOID_OBJ , _VOID_OBJn ) (void) {
    return (void*) & _VOID_NEW_OBJ ;
}
#undef _VOID_NEW_OBJ
#endif //#}

// End of Macros to define a list of pointers to class method structures
// and to bind data types to method types.

#endif //#}
struct impl;
struct impl *make_impl();
// don't use this as it is a reserved keyword in c++
void do_bar(struct impl *myThis, int bar);
$ clang++ -std=c++11 -S -emit-llvm -o out main.cc # Worked
$ llc -march=c out 
llc: error: invalid target 'c'.

 $ clang++ --version
 clang version 3.7.0 (trunk 232670)
Target: x86_64-unknown-linux-gnu
Thread model: posix
#include <stdio.h>

// shared method table structure for all classes
typedef struct {
    void (* init)( void* );
    char* (* tryme)( void*, char* echo );
} poly_method_table;

// define class1
typedef struct {
    char* name;
    int   one;
} class1;
void class1_init( class1* self ) {
    self->name = "test";
    self->one=5;  
}
const poly_method_table class1_mt = {
    .init = class1_init
};

// define class2
typedef struct {
    int x;
} class2;
char* class2_tryme( class2* self, char* echo ) {
    return echo;
}
const poly_method_table class2_mt = {
    .tryme = class2_tryme
};

// global lookup table
const poly_method_table * table_select[] = {
    &class1_mt,
    &class2_mt,
};
#define M(MSG, THIS, ...) table_select[_Generic((THIS), \
    class1 *: 0, \
    class2 *: 1, \
    default: "error")]->MSG((THIS), ## __VA_ARGS__)


int main( void ) {
    class1 a;
    class2 b;

    M( init, &a );
    printf("a=%s %s\n",a.name, M( tryme, &b, "echo is this" ) );
}
#define CLASSES class1, class2 //etc.

#define BUILD_ENUM(class) class ## _enum,
#define BUILD_SELECTOR(class) &class ## _mt,
#define SELECT_CLASS(class) class *: class ## _enum,

#define M(MSG, THIS, ...) table_select[_Generic((THIS), \
  FOR_EACH(SELECT_CLASS, CLASSES) \
  default: "error")]->MSG((THIS), ## __VA_ARGS__)

enum { FOR_EACH(BUILD_ENUM, CLASSES) };
const poly_method_table * table_select[] = {
    FOR_EACH(BUILD_SELECTOR, CLASSES)
};
#define M(MSG, THIS, ...) _Generic((THIS), \
  class1 *: class1_selector((struct class1_ ## MSG ## _dmy*)0), \
  class2 *: class2_selector((struct class2_ ## MSG ## _dmy*)0), \
  default: "error")(THIS, ## __VA_ARGS__)
#define class1_selector(MSG) _Generic((MSG), \
  struct class1_init_dmy *: class1_init, \
  struct class1_show_dmy *: class1_show, \
  struct class1_getOne_dmy *: class1_getOne, \
  default: "error")
#include <stdio.h>

// centralized list of classes
#define CLASSES  class1, class2

// static class dispatch
#define M(MSG, THIS, ...) _Generic((THIS), \
  class1 *: class1_selector((struct class1_ ## MSG ## _dmy*)0), \
  class2 *: class2_selector((struct class2_ ## MSG ## _dmy*)0), \
  default: "error: unknown class")(THIS, ## __VA_ARGS__)


// define class1
typedef struct {
    char* name;
    int   one;
} class1;
void class1_init( class1* self ) {
    self->name = "test";
    self->one=5;  
}
void class1_show(class1 * self) { printf("class1: (%s, %d)\n", self->name, self->one); }
int class1_getOne(class1 * self) { return self->one; }

// class1 static method dispatch table
#define class1_selector(MSG) _Generic((MSG), \
  struct class1_init_dmy *: class1_init, \
  struct class1_show_dmy *: class1_show, \
  struct class1_getOne_dmy *: class1_getOne, \
  default: "error: unknown method")


// define class2
typedef struct {
    int x;
} class2;
void class2_show(class2 * self) { printf("class2: (%d)\n", self->x); }
char* class2_tryme( class2* self, char* echo ) { return echo; }

// class2 static method dispatch table
#define class2_selector(MSG) _Generic((MSG), \
  struct class2_tryme_dmy *: class2_tryme, \
  struct class2_show_dmy *: class2_show, \
  default: "error: unknown method")


int main(void) {
    class1 a;
    class2 b;

    M( init, &a );
    b.x = 13;
    M( show, &a );
    M( show, &b );
}
#include <stdio.h>

// !!METAPROGRAMMING BOILERPLATE
#include "cmacros.h"
// static class dispatch
#define M(MSG, ...) _Generic(M_FIRST(__VA_ARGS__), \
  M_REST(M_REST(M_FOR_EACH(M_RE_EXP, \
    (D1, D2, D3) \
    M_ZIP_WITH(MSG_SEL, (CLASSES), M_ENLIST(MSG, M_NARGS(CLASSES))) ) )) \
  ,default: "error: unknown class") \
  (__VA_ARGS__)

#define M_RE_EXP(E) ,M_FIRST E*: _Generic(DUMMY_SEL(M_FIRST E, M_FIRST(M_REST E)), \
  M_CONC2(M, M_REST(M_REST E)) \
  default: "error: unknown method")

#define M_CONC2(L, R) M_CONC2_(L, R)
#define M_CONC2_(L, R) L##R

#define MSG_SEL(CLASS, MSG) ,MSG_SEL_(CLASS, MSG)
#define MSG_SEL_(CLASS, MSG) (CLASS, MSG, LIST_METHODS(CLASS, CLASS ## _methods))

#define DUMMY_SEL(CLASS, MSG) DUMMY_SEL_(CLASS, MSG)
#define DUMMY_SEL_(CLASS, MSG) (struct CLASS##_##MSG##_dmy*)0

#define LIST_METHODS(CLASS, ...) \
  _ZIP_WITH(METHOD_SEL, M_ENLIST(CLASS, M_NARGS(__VA_ARGS__)), (__VA_ARGS__))
#define METHOD_SEL(CLASS, METH) METHOD_SEL_(CLASS, METH)
#define METHOD_SEL_(CLASS, METH) struct CLASS##_##METH##_dmy*: CLASS##_##METH,
// !!END OF BOILERPLATE


// centralized list of classes
#define CLASSES  class1, class2


// define class1
typedef struct {
    char* name;
    int   one;
} class1;
void class1_init( class1* self ) {
    self->name = "test";
    self->one=5;  
}
void class1_show(class1 * self) { printf("class1: (%s, %d)\n", self->name, self->one); }
int class1_getOne(class1 * self) { return self->one; }

#define class1_methods init, show, getOne


// define class2
typedef struct {
    int x;
} class2;
void class2_show(class2 * self) { printf("class2: (%d)\n", self->x); }
char* class2_tryme( class2* self, char* echo ) { return echo; }

#define class2_methods show, tryme


int main(void) {
    class1 a;
    class2 b;

    M( init, &a );
    b.x = 13;
    M( show, &a );
    M( show, &b );
}