Пусть есть такая структура:

struct _Example {
    int a;
    int b;
    int c;
} Example;

Одна функция берет эту структуру по указателю и выводит значение членов структуры. Я хочу напечатать эти значения следующим образом:

Example example;
func(&example);

if(example.a)
    printf("%d", example.a);

if(example.b)
    printf("%d", example.b);

if(example.c)
    printf("%d", example.c);

Как я могу заменить эти множественные if условия циклом?

c
2
Biswapriyo 21 Авг 2018 в 09:32

3 ответа

Лучший ответ

Наилучшим способом, вероятно, является пробивание типа union. Это позволяет вам использовать одну и ту же область памяти с различными представлениями переменных, например, давая каждому члену структуры индивидуальные имена, в то же время оставаясь в состоянии циклически проходить через них.

#include <stdio.h>

typedef union {
  struct  // anonymous struct, requires standard C compiler
  {
    int a;
    int b;
    int c;
  };
  int array[3];
} Example;


int main (void)
{
  Example ex = { .a=1, .b=2, .c=3 };

  for(size_t i=0; i<3; i++)
  {
    printf("%d\n", ex.array[i]);
  }
}

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

Предполагая, что uint8_t является символьным типом, тогда:

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

typedef union {
  struct
  {
    int a;
    int b;
    int c;
  };
} Example;


int main (void)
{
  Example ex = { .a=1, .b=2, .c=3 };
  uint8_t* begin = (uint8_t*)&ex;
  uint8_t* end   = begin + sizeof ex;


  for(uint8_t* i=begin; i!=end; i+=sizeof(int))
  {
    printf("%d\n", *(int*)i);
  }
}
8
Lundin 21 Авг 2018 в 06:45

Короткий ответ: вы не можете сделать это легко. Элементы в структурах предназначены для доступа по имени, в отличие от элементов в массивах, предназначенных для индексации.

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

Языки, которые переносят информацию о типах в более сложную среду выполнения, такие как C # и Java, позволяют перечислять элементы структуры во время выполнения, но C просто создает неаннотированный большой двоичный объект данных, который вы должны знать во время компиляции В любом случае, вы также можете явно перечислить членов. Конечно, вы можете использовать обычные трюки C; вероятно, существует решение для сериализации, которое генерирует код для доступа к элементам структуры из некоторого определения структуры, заключенного в макрос (ах, да, первое попадание Google: https://gist.github.com/Rhomboid/8e48620badbb3d9b4c30).

Тот факт, что вы можете индексировать элементы массивов во время выполнения, объясняется тем, что внутренняя компоновка массива полностью известна (например, он определен как не содержащий отступов).

Конечно, вы можете определить структуру, которая содержит массив объединений, достаточно большой, чтобы вместить ваш самый крупный элемент, который содержит информацию своего собственного типа и имени «члена», а затем выполняет функции для интерпретации этой информации, вычисления правильного расположения в памяти с использованием соответствующего приведения типа. и printf строка преобразования во время выполнения. По сути, вы подражаете некоторым функциям более сложных сред выполнения.

1
Peter - Reinstate Monica 21 Авг 2018 в 07:24

Если вы рассматриваете struct variable как отдельное, это невозможно

Но если вы рассматриваете их как array, то возможно

Например

struct Example {int member[3];};

int main()
{
     struct Example example;
     int i;
     for (i = 0; i < 3; ++i)
         example.member[i] = i;
}
0
Mr. Roshan 21 Авг 2018 в 06:57
51942867