Как получить доступ к членам 'структуры' согласно переменному целому числу в C?

Никто не может напрямую перейти в ваш репозиторий, если вы еще не предоставляете ему права на запись.

Процесс добавления в общедоступный репозиторий в github начинается с разветвления репозитория, затем помещает изменение на разветвленный , а затем создает запрос извлечения на исходный репозиторий . После этого роль владельца проекта заключается в проверке и принятии мер (слияние / отклонение) запрошенного изменения кода.

Для получения более подробной информации, пожалуйста, проверьте следующую полезную статью:

https://akrabat.com/the-beginners-guide-to-contributing-to-a-github- проект

9
задан Ori Popowski 20 May 2009 в 13:20
поделиться

11 ответов

Если у вас нет конкретных знаний о базовой структуре структуры, нет способа реализовать такой метод в C. Есть всевозможные проблемы, которые будут мешать, включая

  • Члены разного размера
  • Проблемы с упаковкой
  • Проблемы с выравниванием
  • Уловки, такие как битовые поля, будут проблематичными

Лучше всего реализовать метод для своей структуры вручную, который имеет глубокое понимание внутренних членов структура.

13
ответ дан 4 December 2019 в 07:35
поделиться

Если бы ваша структура была чем-либо, кроме битовых полей, вы могли бы просто использовать доступ к массиву, если я прав в том, что помню, что C гарантирует, что ряд членов структуры одного типа имеет тот же макет, что и массив. Если вы знаете, какие биты в каком порядке ваш компилятор хранит битовые поля в целочисленные типы, вы можете использовать операции сдвига / маски, но тогда это зависит от реализации.

Если вы хотите получить доступ к битам по индексу переменной, то, вероятно, лучше всего замените битовые поля целым числом, содержащим биты флагов. Доступ по переменной на самом деле не то, для чего нужны битовые поля: a1 ... an в основном независимые члены, а не массив битов.

Вы можете сделать что-то вроде этого:

struct Element {
    unsigned int a1 : 1;
    unsigned int a2 : 1;
    ...
    unsigned int an : 1;
};

typedef unsigned int (*get_fn)(const struct Element*);

#define DEFINE_GETTER(ARG) \
    unsigned int getter_##ARG (const struct Element *ep) { \
        return ep-> a##ARG ; \
    }

DEFINE_GETTER(1);
DEFINE_GETTER(2);
...
DEFINE_GETTER(N);

get_fn jump_table[n] = { getter_1, getter_2, ... getter_n};

int getval(struct Element *ep, int n) {
    return jump_table[n-1](ep);
}

И некоторых повторений можно избежать, если трюк, когда вы включаете один и тот же заголовок несколько раз, каждый раз определив макрос по-разному. Заголовок раскрывает этот макрос один раз для каждого 1 ... N.

Но я не уверен, что оно того стоит.

Это действительно связано с точкой зрения JaredPar о том, что у вас проблемы, если ваша структура смешивает разные типы - здесь все элементы, к которым осуществляется доступ через определенную таблицу переходов, конечно, должны быть одного типа, но между ними может быть какой-то старый мусор. Тем не менее, это по-прежнему оставляет остальную часть замечаний JaredPar, и это большой объем кода, который действительно не дает преимуществ по сравнению с переключением.

у вас возникнут проблемы, если ваша структура смешивает разные типы - здесь все члены, к которым осуществляется доступ через определенную таблицу переходов, конечно, должны быть одного типа, но между ними может быть какой-то старый мусор. Тем не менее, это по-прежнему оставляет остальную часть замечаний JaredPar, и это большой объем кода, который действительно не дает преимуществ по сравнению с переключением.

у вас возникнут проблемы, если ваша структура смешивает разные типы - здесь все члены, к которым осуществляется доступ через определенную таблицу переходов, конечно, должны быть одного типа, но между ними может быть какой-то старый мусор. Тем не менее, это по-прежнему оставляет остальную часть замечаний JaredPar, и это большой объем кода, который действительно не дает преимуществ по сравнению с переключением.

6
ответ дан 4 December 2019 в 07:35
поделиться

Я предлагаю генерацию кода. Если ваши структуры не содержат большого количества полей, вы можете автоматически создавать процедуры для каждого поля или для ряда полей. и используйте их как:

val = getfield_aN( myobject, n );

или

val = getfield_foo( myobject );
0
ответ дан 4 December 2019 в 07:35
поделиться

Если у вас есть

  1. Только битовые поля или все битовые поля сначала в структуре
  2. меньше 32 (или 64) битовых полей

, то это решение для вас.

#include <stdio.h>
#include <stdint.h>

struct Element {
  unsigned int a1 : 1;
  unsigned int a2 : 1;
  unsigned int a3 : 1;
  unsigned int a4 : 1;
};

#define ELEMENT_COUNT 4 /* the number of bit fields in the struct */

/* returns the bit at position N, or -1 on error (n out of bounds) */
int getval(struct Element* ep, int n) 
{
  if(n > ELEMENT_COUNT || n < 1)
    return -1;

  /* this union makes it possible to access bit fields at the beginning of 
     the struct Element as if they were a number.
   */
  union {
    struct Element el;
    uint32_t bits;
  } comb;

  comb.el = *ep;
  /* check if nth bit is set */
  if(comb.bits & (1<<(n-1))) {
    return 1;
  } else {
    return 0;
  }
}

int main(int argc, char** argv)
{
  int i;
  struct Element el;

  el.a1 = 0;
  el.a2 = 1;
  el.a3 = 1;
  el.a4 = 0;

  for(i = 1; i <= ELEMENT_COUNT; ++i) {
    printf("el.a%d = %d\n", i, getval(&el, i));
  }  

  printf("el.a%d = %d\n", 8, getval(&el, 8));

  return 0;
}
0
ответ дан 4 December 2019 в 07:35
поделиться

If you want to access your structure using both element index:

int getval(struct Element *ep, int n)

and by name:

ep->a1

then you are stuck with some hard to maintain switch like method that everyone has suggested.

If, however, all you want to do is access by index and never by name, then you can be a bit more creative.

First off, define a field type:

typedef struct _FieldType
{
    int size_in_bits;
} FieldType;

and then create a structure definition:

FieldType structure_def [] = { {1}, {1}, {1}, {4}, {1}, {0} };

The above defines a structure with five elements of size 1, 1, 1, 4 and 1 bits. The final {0} marks the end of the definition.

Now create an element type:

typedef struct _Element
{
    FieldType *fields;
} Element;

To create an instance of an Element:

Element *CreateElement (FieldType *field_defs)
{
  /* calculate number of bits defined by field_defs */
  int size = ?;
  /* allocate memory */
  Element *element = malloc (sizeof (Element) + (size + 7) / 8); /* replace 7 and 8 with bits per char */
  element->fields = field_defs;
  return element;
}

And then to access an element:

int GetValue (Element *element, int field)
{
   /* get number of bits in fields 0..(field - 1) */
   int bit_offset = ?;
   /* get char offset */
   int byte_offset = sizeof (Element) + bit_offset / 8;
   /* get pointer to byte containing start of data */
   char *ptr = ((char *) element) + byte_offset;
   /* extract bits of interest */
   int value = ?;
   return value;
}

Setting values is similar to getting values, only the final part needs changing.

You can enhance the above by extending the FieldType structure to include information about the type of value stored: char, int, float, etc, and then write accessors for each type which checks the required type against the defined type.

0
ответ дан 4 December 2019 в 07:35
поделиться

Почему бы не встроить getval () в структуру?

struct Whang {
    int a1;
    int a2;
    int getIth(int i) {
        int rval;
        switch (i) {
            case 1: rval = a1; break;
            case 2: rval = a2; break;
            default : rval = -1; break;
        }
        return rval;
    }
};    

int _tmain(int argc, _TCHAR* argv[])  
{  
        Whang w;  
    w.a1 = 1;  
    w.a2 = 200;

    int r = w.getIth(1);

    r = w.getIth(2);

    return 0;
}

getIth () должен знать внутреннее устройство Whang и иметь дело со всем, что он содержит.

0
ответ дан 4 December 2019 в 07:35
поделиться

Если структура действительно настолько проста, как описано, вы можете использовать объединение с массивом (или преобразование в массив) и некоторый бит - магия доступа (как в Как вы устанавливаете, очищаете и переключаете один бит в C? ).

Как говорит Джаред, в общем случае сложный .

0
ответ дан 4 December 2019 в 07:35
поделиться

Если каждое поле в вашей структуре представляет собой int , тогда вы должны иметь возможность сказать

int getval(struct Element *ep, int n)
{
    return *(((int*)ep) + n);
}

Это переводит указатель на вашу структуру в указатель на массив если целые числа, то обращается к n-му элементу этого массива. Поскольку все в вашей структуре кажется целым числом, это совершенно верно. Обратите внимание, что это приведет к ужасной неудаче, если у вас когда-либо будет член, не являющийся int.

Более общим решением было бы поддержание массива смещений полей:

int offsets[3];
void initOffsets()
{
    struct Element e;
    offsets[0] = (int)&e.x - (int)&e;
    offsets[1] = (int)&e.y - (int)&e;
    offsets[2] = (int)&e.z - (int)&e;
}

int getval(struct Element *ep, int n)
{
    return *((int*)((int)ep+offsets[n]));
}

Это будет работать в том смысле, что вы сможете вызывать getval для любого из полей int вашей структуры, даже если у вас есть другие поля, отличные от int, в вашей структуре, поскольку все смещения будут правильными. Однако, если вы попытаетесь вызвать getval для одного из полей, отличных от int, оно вернет совершенно неверное значение.

Конечно, вы можете написать отдельную функцию для каждого типа данных, например,

double getDoubleVal(struct Element *ep, int n)
{
    return *((double*)((int)ep+offsets[n]));
}

, а затем просто вызвать соответствующую функцию для любого типа данных, который вам нужен. Между прочим, если бы вы использовали C ++, вы могли бы сказать что-то вроде

template<typename T>
T getval(struct Element *ep, int n)
{
    return *((T*)((int)ep+offsets[n]));
}

, и тогда это сработало бы для любого типа данных, который вам нужен.

7
ответ дан 4 December 2019 в 07:35
поделиться

Нет, нет простого способа сделать это проще. Особенно для битовых полей, к которым трудно получить косвенный доступ через указатели (вы не можете взять адрес битового поля).

Вы, конечно, можете упростить эту функцию до чего-то вроде этого:

int getval(const struct Element *ep, int n)
{
    switch(n)
    {
      case 1: return ep->a1;
      case 2: return ep->a2;
      /* And so on ... */
    }
    return -1; /* Indicates illegal field index. */
}

И кажется очевидным, как может быть реализована реализация дополнительно упрощается с помощью макроса препроцессора, который расширяется до строки case , но это всего лишь сахар .

3
ответ дан 4 December 2019 в 07:35
поделиться

Я думаю, что ваше настоящее решение - не использовать битовые поля в вашей структуре, а вместо этого определить либо установленный тип, либо битовый массив.

0
ответ дан 4 December 2019 в 07:35
поделиться

Никогда не обращайтесь к бизнес-компонентам из представлений jsp; что-то вроде sitemesh можно использовать для объединения нескольких видов в одном. Jsps также не должен вызывать методы контроллера напрямую

-121--2489349-

Допустим, вы найдете ответ здесь. Думаю, вам нужно подумать, как будет выглядеть «решение» для следующего парня, который смотрит на ваш код.

Я возьму более читаемый код по сравнению с парой миллисекунд в любой день.

-121--4294025-

На основе решения eli-courtwright, но без использования массива смещений полей ...... если у вас есть структура, содержащая такое поле указателя, возможно, вы могли бы написать:

struct  int_pointers
 {
   int  *ptr1;
   int  *ptr2;
   long *ptr3;
   double *ptr4;
   std::string * strDescrPtr;

};

Тогда вы знаете, что каждый указатель имеет смещение 4 байта от указателя на структуру, так что вы можете записать:

struct int_pointers  ptrs;
int  i1 = 154;
int i2 = -97;
long i3 = 100000;
double i4  = (double)i1/i2;
std::string strDescr = "sample-string";
ptrs.ptr1 =  &i1;
ptrs.ptr2 =  &i2;
ptrs.ptr3 = &i3;
ptrs.ptr4 = &i4;
ptrs.strDescrPtr = &strDescr;

Тогда, например, для значения int можно записать:

int GetIntVal (struct int_pointers *ep, int intByteOffset) 
{ 
   int * intValuePtr =  (int *)(*(int*)((int)ep + intByteOffset)); 
   return *intValuePtr; 
}

Вызывая его:

int intResult = GetIntVal(&ptrs,0) //to retrieve the first int value in ptrs structure variable

int intResult = GetIntVal(&ptrs,4) //to retrieve the second int value in ptrs structure variable

и так далее для других значений полей структуры (запись других специфических функций и использование правильного значения смещения байтов (кратного 4)).

0
ответ дан 4 December 2019 в 07:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: