Что означает "++" после объединения в C? - PullRequest
2 голосов
/ 29 января 2020

Вот код

int AreSymEquivalent_hkl(const T_SgInfo *SgInfo, int h1, int k1, int l1,
                                                 int h2, int k2, int l2)
{
  int     iList, mh2, mk2, ml2, hm, km, lm;
  T_RTMx  *lsmx;


  mh2 = -h2;
  mk2 = -k2;
  ml2 = -l2;

  /* check list of symmetry operations */

  lsmx = SgInfo->ListSeitzMx;

  for (iList = 0; iList < SgInfo->nList; iList++, lsmx++)
  {
    hm = lsmx->s.R[0] * h1 + lsmx->s.R[3] * k1 + lsmx->s.R[6] * l1;
    km = lsmx->s.R[1] * h1 + lsmx->s.R[4] * k1 + lsmx->s.R[7] * l1;
    lm = lsmx->s.R[2] * h1 + lsmx->s.R[5] * k1 + lsmx->s.R[8] * l1;

    if      ( h2 == hm &&  k2 == km &&  l2 == lm)
      return  (iList + 1);

    else if (mh2 == hm && mk2 == km && ml2 == lm)
      return -(iList + 1);
  }

  return 0;
}

Это функция, определенная из довольно известного пакета 'sginfo' в области вычислительной кристаллографии. (Вы можете скачать отсюда, если хотите: https://github.com/rwgk/sginfo/tree/master/sginfo_1_01) Так что я уверен, что в этом нет ошибки. Вопрос в строках

  lsmx = SgInfo->ListSeitzMx;

  for (iList = 0; iList < SgInfo->nList; iList++, lsmx++)

Где "SgInfo" - это большая структура, которую я здесь не поместил, содержащая "ListSeitzMx" - атрибут объединения с именем "T_RTMx", который содержит информацию о некоторых матрицах , Определение следующее:

typedef union
  {
    struct { int R[9], T[3]; } s;
    int                        a[12];
  }
  T_RTMx;

Это часть меня смущает, "++" после объединения. Что я знаю, так это то, что значение int перед "++" добавляет к 1, но тип объединения не имеет смысла. Или я сделал большую ошибку всего этого? То, что «lsmx» не является объединением или чем-то ... Как новичок C, я пытался написать небольшой тестовый сценарий по этому вопросу, но ошибки сводили меня с ума. Поэтому я наконец решил опубликовать sh этот вопрос ...

Ответы [ 2 ]

4 голосов
/ 29 января 2020
lsmx++

эквивалентно

( orig = lsmx, lsmx = lsmx + 1, orig )

Другими словами,

  • lsmx++ добавляет один к lsmx (как если бы вы сделали ( lsmx = lsmx + 1).

  • lsmx++ соответствует исходному значению lsmx, но оно игнорируется в вашем коде.

lsmx - это указатель. Добавление 1 к указателю увеличивает адрес на размер остроконечной вещи (sizeof(*lsmx)).

Например,

T_RTMx foo[5] = ...;
T_RTMx *lsmx = foo;   # Same as &( foo[0] )   # Points to foo[0]
lsmx++;                                       # Points to foo[1]
lsmx += 2;                                    # Points to foo[3]

Сохранить в помните, что a[b] полностью эквивалентно *(a+b).

2 голосов
/ 29 января 2020

Вы на самом деле не добавляете в союз. Вы добавляете к адресу.

Рассмотрите похожую ситуацию:

struct abc {
    int a, b, c;
    //Lots more nonsense
};

Сейчас,

struct abc z;
struct abc *a;
a = &z

Это говорит о том, что a хранит адрес struct abc type.

Теперь давайте рассмотрим, как работают указатели.

Предположим, что z находится в местоположении 1000. a сохранил это значение. Когда я делаю *a, я обращаюсь к ячейке памяти 1000 до sizeof(struct abc). Поскольку a является указателем на тип struct abc, вы можете сделать:

a->c = 2;

или что-то в этом роде.

Когда вы говорите:

int *b;

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

b = &z;

Вы можете или не можете получать предупреждения в зависимости от вашего компилятора.

Когда я храню &z, единственное, что компилятор обрабатывает значение по адресу z как int. Итак, b имеет значение 1000.

Теперь, когда вы делаете *b, вы ссылаетесь на адрес 1000 до sizeof(int).

В заключение

b++;

Это просто сделает 1000 + sizeof(int), и достигнет следующего int.

a++;

сделает 1000 + sizeof(struct abc).

...