Вопрос

В моей встроенной программе на языке Си у меня есть структура:

struct var{
    unsigned long value;
    unsigned long length;

    + More
}

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

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

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

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

или

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

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

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

Это было полезно?

Решение

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

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

unsigned long *starting_address;

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

Другие советы

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

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

     + More
 }

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

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

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

    + More
}

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

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

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

   unsigned long othervalue1;
   unsigned long othervalue2;
};

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

unsigned long value[50];

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

Если не было задействовано приведение или расширение знака, фактические данные те же.Просто sprintf по-другому интерпретирует это.

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

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

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

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

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

  unsigned long length;
  + More
};

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

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

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

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;

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

Знаете ли вы о offsetof?http://en.wikipedia.org/wiki/Offsetof

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top