C Указатель Вопрос - PullRequest
       11

C Указатель Вопрос

3 голосов
/ 29 июля 2009

В моей встроенной c-программе у меня есть структура:

struct var{
    unsigned long value;
    unsigned long length;

    + More
}

Массив этих структур используется для хранения переменных. Большинство сохраненных переменных просто хранятся в «значении», поэтому длина установлена ​​в 1.
Однако некоторые из этих переменных являются массивами, и я пытаюсь сохранить начальный адрес в «значении».

unsigned long lookup[10];
variables[x].length = 10;

Тогда я не совсем уверен, как сохранить адрес ...

variables[x].value = lookup;
// lookup is a pointer so I cant put it into value

OR

variables[x].value = (unsigned long)lookup;
// value reads back through sprintf+uart as '536874692'
// which couldnt be a valid memory address!

Я мог бы просто сдаться и добавить переменную-указатель в структуру

EDIT:
Я хотел избежать добавления указателя в структуру, потому что мне пришлось бы вернуться и переписать функции чтения / записи флэш-памяти, чтобы также сохранить указатель. Они довольно сложные и в настоящее время работают, поэтому я бы не стал их трогать!

Ответы [ 10 ]

6 голосов
/ 29 июля 2009

Более чистым вариантом будет использование union .

 struct var{
     union {
        unsigned long numeric;
        void *ptr;  
     } value;
     unsigned long length;

     + More
 }

При желании вы также можете включить enum типа, как это часто делается для штук, использующих объединение.

5 голосов
/ 29 июля 2009

Вы могли бы сохранить адрес в value, приведя его к unsigned long, как вы продемонстрировали. (Я думаю, что значение, которое вы получаете , является действительным адресом ... в шестнадцатеричном виде, оно выглядит как 0x20000EC4 ... похоже, сегмент данных вашей встроенной системы начинается с 0x20000000, а?)

Однако приведение указателей к целым (или длинным) типам никогда не бывает «чистым». Почему бы не добавить

unsigned long *starting_address;

к вашей структуре? Тогда вы можете избежать Typecasts. Если вы беспокоитесь, что для этого потребуется больше памяти, вы можете использовать объединение, в котором хранится либо unsigned long *starting_address, либо «длинное значение без знака», которое по-прежнему чище, чем приведение.

1 голос
/ 29 июля 2009

Предполагая, что размер системного указателя такой же, как у unsigned long (без гарантии, проверьте его с помощью sizeof), который вы бы использовали приведения. Но это грязно и подвержено ошибкам. Попробуйте вместо этого использовать объединение.

struct var{
    unsigned short type;
    union {
        unsigned long i;
        void *p;
    } value;
    unsigned long length;

    + More
}

где вы храните тип в type.

0 голосов
/ 29 июля 2009

Вам известно о смещении? http://en.wikipedia.org/wiki/Offsetof

Я не уверен, что вы действительно пытаетесь сделать, но сохранение адреса одного члена структуры в той же структуре кажется ненужным.

Существует также макрос container_of (google it), который построен с использованием offsetof и который также может быть полезен.

0 голосов
/ 29 июля 2009

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

0 голосов
/ 29 июля 2009

Ваш лучший выбор - использовать enum , как уже говорилось:

typedef struct var{
     union {
        unsigned long numeric;
        void *ptr;  
     } value;
     unsigned long length;

     // + More
 } composition_t;

затем используйте элемент длина , чтобы различать тип данных:

composition_t array[2];
unsigned long lookup[10];

// Just a plain unsigned long value
array[0].value.numeric = 100;
array[0].length= 1;

// An array of 10 long values
array[0].value.ptr= lookup;
array[x].length = 10;
0 голосов
/ 29 июля 2009

Я не уверен, почему вы не определяете значение как длинную без знака *.

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

struct var{
  union{
    unsigned long solo_value;
    unsigned long* multi_values;
  }

  unsigned long length;
  + More
};

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

* Технически malloc () et. и др. применять 8-байтовые правила выравнивания, а не язык.

0 голосов
/ 29 июля 2009

Почему бы не сделать значение массивом из одной длины, если длина равна 1? В любом случае, вы не будете использовать больше места.

0 голосов
/ 29 июля 2009

Что произойдет, если вы выполните поиск sprintf + uart. Какую ценность это дает вам?

Если не было задействовано расширение приведения или подписи, фактические данные совпадают. Это просто по-разному интерпретируется sprintf.

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

0 голосов
/ 29 июля 2009

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

struct var
{
   unsigned long *value;
   unsigned long length;

   unsigned long othervalue1;
   unsigned long othervalue2;
};

Но не забудьте выделить память для значения отдельно, используя malloc. Или, если это фиксированное количество места, которое вы хотите использовать

unsigned long value[50];
...