2015-12-21 3 views
0

Внутри структуры мне нужно место, где я могу что-то вставить. Это пространство должно иметь возможность собирать все типы данных, поэтому я хочу определить объединение. Пространство ограничено n байтами (unsigned char).C Union definition

Как мне определить мой союз, чтобы он мог содержать char, int, float и т. Д.?

Должен ли я так поступать?

#define SIZE (128) 
union { 
     unsigned char uchar[SIZE]; 
     char schar[SIZE]; 
     unsigned int uint[SIZE/sizeof(unsigned int)]; 
     int sint[SIZE/sizeof(int)]; 
     float flt[SIZE/sizeof(float)]; 
     double dbl[SIZE/sizeof(double)]; 
}memory; 

Или есть возможность определить только размер без знака массив символов, а затем автоматически определять размер Int массива? Что произойдет, если SIZE не делится на 4?

EDIT: (в связи с комментариями)

Я хочу построить что-то вроде приурочено обработчик события. Это означает, что у меня есть структура, содержащая массив событий. Каждое событие имеет время выполнения и связанную функцию (хранится как указатель). Когда счетчик таймера обработчика событий соответствует времени выполнения события, я вызываю связанную функцию. Внутри функции я буду знать, какие аргументы ожидаются, поэтому мне не нужно сохранять значение тега. Проблема в том, что события создаются в funtion, и поскольку я не хочу, чтобы события статичны (чтобы сохранить память), я добавил некоторую память (кольцевой буфер) в обработчик событий, где все функции могут помещать некоторые данные , Каждое событие будет иметь переменную, содержащую указатель на (первые) данные. Тип данных - это только типы данных nativ, не собственные структуры.

Это мой текущий код:

startSystemClock() будет называться при запуске

executeSystemEvent() будет вызываться процедура обработки прерываний таймера 1, установив sysEventHandler.execute=TRUE и А while(1) -loop проверяет этот флаг, а затем звонки executeSystemEvent()

// typedefs requird for timed events 
typedef union __attribute__ ((packed)){ 
    int *i;  // pointer, where data is stored 
    int value; // if there is a pointer assigned, value differs from zero 
}systemEventData_u; 

typedef union __attribute__ ((packed)){ 
    int value; // if there is a pointer assigned, value differs from zero 
    void (*voidFct_noData)(); 
    void (*voidFct_data)(systemEventData_u); 
}systemEventFct_u; 

typedef struct{ 
    int time; 
    unsigned int id; 
    systemEventFct_u fct; 
    systemEventData_u data; 
}systemEvent_t; 

#define SYSTEM_EVENT_HANDLER_BUFFER_SIZE (10) 
#define SYSTEM_EVENT_HANDLER_MEMORY_SIZE (10) 
typedef struct{ 
    unsigned int actualCnt; 
    unsigned int nextEventCnt; 
    unsigned char execute; 
    systemEvent_t events[SYSTEM_EVENT_HANDLER_BUFFER_SIZE]; 
    systemEvent_t* write; 
    // create some persistent memory usable by all functions 
    int* memWrite; 
    union __attribute__ ((packed)){ 
     unsigned char uchar[0]; 
     char schar[0]; 
     unsigned int uint[0]; 
     int sint[SYSTEM_EVENT_HANDLER_MEMORY_SIZE]; 
     float flt[0]; 
     double dbl[0]; 
    }memory; 
}systemEventHandler_t; 

void startSystemClock(){ 
    // initialize event handler 
    sysEventHandler.actualCnt=0; 
    sysEventHandler.nextEventCnt=-1; 
    sysEventHandler.execute=FALSE; 
    sysEventHandler.write=sysEventHandler.events; 
    sysEventHandler.memWrite=sysEventHandler.memory.sint; 
    unsigned int i=SYSTEM_EVENT_HANDLER_BUFFER_SIZE; 
    systemEvent_t *ptr=sysEventHandler.events; 
    while(i--){ 
     ptr->fct.value=0; 
     ptr->data.value=0; 
     ptr->time=0; 
     ptr++; 
    } 
    // initialize timer 1 
    TMR1 = 0x00; 
    T1CON = T3_OFF | T3_IDLE_CON | T3_GATE_OFF | T1_PS_1_8 | T1_SOURCE_INT; 
    IPC1SET = (INTERRUPT_PRIOR_TIMER1 << _IPC1_T1IP_POSITION) | (INTERRUPT_SUB_PRIOR_TIMER1 << _IPC1_T1IS_POSITION); 
    IFS0CLR = (1 << _IFS0_T1IF_POSITION); 
    IEC0SET = (1 << _IEC0_T1IE_POSITION); 
    PR1 = PR_TIMER1; 
    T1CONSET = (1 << _T1CON_ON_POSITION); 
    print_text("timer1 started\n\r"); 
} 

void executeSystemEvent(){ 
    asm("di"); 
    int time=sysEventHandler.actualCnt; 
    asm("ei"); 
    unsigned int i=SYSTEM_EVENT_HANDLER_BUFFER_SIZE; 
    unsigned int nextEventCnt=-1; 
    systemEvent_t *ptr=sysEventHandler.events; 
    while(i--){ 
     // do not investigate, if there is no function pointer 
     // no function pointer means no event action 
     if(ptr->fct.value){ 
      if(time>=ptr->time){ 
       // execute function 
       if(ptr->data.value){ 
        (*ptr->fct.voidFct_data)(ptr->data); 
       }else{ 
        (*ptr->fct.voidFct_noData)(); 
       } 
       ptr->fct.value=0; 
      } 
     } 
     ptr++; 
    } 
    // determine next event 
    // iterate again through whole queue to take added events into account also 
    i=SYSTEM_EVENT_HANDLER_BUFFER_SIZE; 
    ptr=sysEventHandler.events; 
    while(i--){ 
     if(ptr->fct.value){ 
      // get execution time to determine next one 
      if(ptr->time<nextEventCnt){ 
       nextEventCnt=ptr->time; 
      } 
     } 
     ptr++; 
    } 
    asm("di"); 
    sysEventHandler.nextEventCnt=nextEventCnt; 
    sysEventHandler.execute=FALSE; 
    asm("ei"); 
} 

void addSystemEvent(systemEvent_t event){ 
    // check, if this event will be the first event to execute 
    asm("di"); 
    // get event execution time 
    event.time+=sysEventHandler.actualCnt; 
    // check, if it will be the next one to execute 
    if(sysEventHandler.nextEventCnt>event.time){ 
     sysEventHandler.nextEventCnt=event.time; 
    } 
    asm("ei"); 
    *sysEventHandler.write=event; 
    if(++sysEventHandler.write>=sysEventHandler.events+SYSTEM_EVENT_HANDLER_BUFFER_SIZE){ 
     sysEventHandler.write=sysEventHandler.events; 
    } 
} 

int * storeSystemEventData(int data){ 
    int *ptr=sysEventHandler.memWrite; 
    *ptr=data; 
    if(++sysEventHandler.memWrite>=sysEventHandler.memory.sint+SYSTEM_EVENT_HANDLER_MEMORY_SIZE){ 
     sysEventHandler.memWrite=sysEventHandler.memory.sint; 
    } 
    return ptr; 
} 

Чтобы добавить событие, я пишу в любой функции:

systemEvent_t event; 
event.fct.voidFct_data=&enablePinChangeInterrupt_wrapper; 
event.data.i=storeSystemEventData((int)PUSHBUTTON_CN_BIT); 
event.time=10; 
addSystemEvent(event); 

Я знаю, что storeSystemEventData -функция не является полной. Но для моей первой цели мне нужен только int, поэтому он работает.

+0

Когда вы говорите, что все типы данных имеют в виду только обычные типы данных, такие как 'int' и т. Д., Или вам также нужны пользовательские типы данных, такие как' struct'? Вам нужно рассмотреть другие более конкретные типы данных, такие как 32-битные или 64-битные целые числа с подписью/без знака? Вам действительно нужны массивы типов, отличных от 'char' и' unsigned char', поскольку эти массивы обычно используются для текстовых строк или это пространство памяти, которое будет использоваться для размещения текстовой строки или двоичного числа? –

+0

Еще один вопрос: как узнать, какой тип данных хранится в объединении? Обычно объединение используется внутри структуры, которая содержит значение тега или перечисление, которое указывает фактический тип данных, хранящийся в объединении. –

+0

см. Редактировать –

ответ

3

Вам не нужно указывать размеры массива, кроме самых больших. Просто за пределами доступа к другим типам.

#include "stdio.h" 

union memory { 
    unsigned char uchar[128]; 
    char schar[0]; 
    unsigned int uint[0]; 
    int sint[0]; 
    float flt[0]; 
    double dbl[0]; 
} ; 

int main (void) 
{ 
    union memory my_mem; 
    my_mem.schar[5] = 'A'; 
    my_mem.schar[6] = 'B'; 
    my_mem.schar[7] = 'C'; 
    my_mem.schar[8] = 'D'; 

    printf ("%d\n", my_mem.uint[1]); 
    return 0; 
} 

C не обеспечивает проверку границ массива в любом случае, так что вы просто не повезло, если вы пытаетесь получить доступ к памяти за пределами объекта памяти.

+0

Это обычный способ установить размер массивов в ноль или это более распространенный используемый «взлом»? –

+0

Не то, чтобы я знал. Обычного взлома нет, потому что очень редко писать код с помощью таких союзов. – QuestionC

+0

Что было бы подходящим способом сделать то, что я хочу? –

2

Что происходит, если SIZE не делится на 4?

Я предполагаю, что вы задаете вопрос о делимости на 4 (в отличие от любого другого номера), потому что это общий sizeof(int). Когда SIZE неделимо ни одним из sizeof s, в итоге окажется самый большой массив, который полностью помещается внутри size, т. Е. Число будет усечено.Например, установка SIZE к 13, когда sizeof(int) равно 4 будет производить

int sint[3]; 

Другими словами, размер будет «округляется вниз» (усеченный). Если вы предпочитаете округление, используйте это выражение:

unsigned int uint[(SIZE+sizeof(unsigned int)-1)/sizeof(unsigned int)]; 

Однако следует отметить, что размер uint[] массива может превышать размер uchar.

Есть ли возможность определить только размер массива без знака, а затем определить размер массива int автоматически?

Вы могли бы заменить union с массивом char с, и преобразовать void* указатель int*, float* и т.д. Это приведет к другому синтаксису.

+1

@nouney В случае aliased массивов 'void *' лучше, потому что он обеспечивает большую ясность читателям вашего кода. Я часто предпочитаю 'char *' to 'void *', когда мне нужно разделить мои блоки памяти вручную, потому что 'char *' позволяет мне делать арифметику указателя без приведения. – dasblinkenlight

+0

* Вы можете заменить объединение массивом символов и преобразовать указатель void * в int *, float * и т. Д. * Я бы заметил, что это может привести к сбоям, таким как SIGBUS на архитектурах с различными ограничениями выравнивания для разных данных типы. Если бы, например, явный массив 'double' в союзе избежал бы этого. Кроме того, как вы намекаете, арифметика указателя на 'void *' является нестандартной - я подозреваю, что ваш комментарий будет генерировать некоторые «Но я все время выполняю арифметику указателей на' void * '!» мысли, если не актуальные комментарии ... –