Дополните структуру C++ к питанию два

Синтезаторы цифровой музыки.

я думаю, целая музыкальная сцена была затронута доступностью дешевых полифонических синтезаторов. Ранние полифонические синтезаторы, где эффективно несколько аналоговых синтезаторов (дискретный или использующий CEM или микросхемы SSM). Они были и дорогими и очень liited. В течение 80-х первые цифровые системы прибыли (я не уверен, но я думаю, что Kurzweil был одним из первых). Сегодня, главным образом все являются цифровыми - даже аналоговые обычно являются "виртуальным anlog".

отношения

РЕДАКТИРОВАНИЕ: ой - я просто узнал, что CMI fairlight был изобретен в 1978. Поэтому забудьте вышеупомянутое - извините.

10
задан Nick Meyer 6 August 2009 в 15:55
поделиться

11 ответов

Используйте метапрограмму шаблона. (Отредактировано в ответ на комментарий).

#include <iostream>
#include <ostream>
using namespace std;

template <int N>
struct P
{
    enum { val = P<N/2>::val * 2 };
};

template <>
struct P<0>
{
    enum { val = 1 };
};

template <class T>
struct PadSize
{
    enum { val = P<sizeof (T) - 1>::val - sizeof (T) }; 
};

template <class T, int N>
struct PossiblyPadded
{
    T       payload;
    char    pad[N]; 
};

template <class T>
struct PossiblyPadded<T, 0>
{
    T       payload;
};

template <class T>
struct Holder : public PossiblyPadded<T, PadSize<T>::val>
{
};


int main()
{
    typedef char Arr[6];

    Holder<Arr> holder;
    cout << sizeof holder.payload << endl;

    // Next line fails to compile if sizeof (Arr) is a power of 2
    // but holder.payload always exists
    cout << sizeof holder.pad << endl;
}
15
ответ дан 3 December 2019 в 13:56
поделиться

Вероятно, наиболее очевидным способом было бы просто использовать тернарный оператор:

#define LOG2_CONST(n) ((n) <= 1 ? 0 :
                      ((n) <= 2 ? 1 :
                      ((n) <= 4 ? 2 :
                      /* ... */
                      ))))))))))))))))))))))))))))))
#define PADDED_STRUCT(ResultName, BaseName) \
  typedef union { BaseName data; char pad[1 << LOG2_CONST(sizeof(BaseName))]; } ResultName
6
ответ дан 3 December 2019 в 13:56
поделиться

Почему бы не использовать объединение?

union Message
{
    struct internal_
    {
        unsigned long member1;
        /* more members */
    };
    char[64];
};

или еще лучше использовать анонимные структуры

union Message
{
    struct
    {
        unsigned long member1;
        /* more members */
    };
    char[64];
};

Таким образом, вы можете получить доступ к членам следующим образом: Message.member1;

Изменить: очевидно, это не решает вашу проблему больше 64, но обеспечивает более чистый способ заполнения.

5
ответ дан 3 December 2019 в 13:56
поделиться

Вы уже используете #pragma pack , я не знаю, какой компилятор (ы) вы используете конкретно, но вы должны посмотреть, поддерживают ли они аргументы для пакета, который контролируйте выравнивание / заполнение, а затем вы можете просто полностью избавиться от поля заполнения. Я знаю, что MSVC версия пакета прагм поддерживает это, как и GCC .

2
ответ дан 3 December 2019 в 13:56
поделиться

Одним из способов решения проблемы было бы заменить жестко запрограммированный 64 с кратным размеру (длинным), превращая заполнение примерно в следующее:

char pad[4*sizeof(unsigned long) - sizeof(internal_)];

Это некрасиво, но должно быть переносимым на 64-битные.

Тем не менее, API, который требует, чтобы размер сообщения был мощным из 2 звучит немного странно и похоже на проблему дизайна. Требовать, чтобы размер был четным числом, имеет смысл, поскольку на некоторых процессорах взимается штраф за доступ к данным по нечетным адресам, но ваш пакет #pragma почти делает это неизбежным.

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

Вы можете макрос это следующим образом (для 32-битной архитектуры):

#define align_step(N, shift) ((N) | ((N) >> shift))
#define align_up(N) (align_step(align_step(align_step(align_step(align_step((N)-1, 1), 2), 4), 8), 16) + 1)
#define alignment_padding(N) (align_up((N)) - (N))

Затем вы можете применить это, используя уловку объединения или другие средства. В вашем примере:

#pragma pack(1)
struct Message
{
   struct internal_
   {
      unsigned long member1;
      unsigned long member2;
      unsigned long member3;
      /* more members */
   } internal;
   char pad[alignment_padding(sizeof(internal_))];
};
#pragma pack()
2
ответ дан 3 December 2019 в 13:56
поделиться

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

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

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

template<int N, int C = 1>
struct Recurse
{
    enum {result = Recurse<N/2, C*2>::result};
};

template<int C>
struct Recurse<0, C>
{
    enum {result = C};
};

template<typename T>
struct Calc
{
    enum {size = Recurse<sizeof(Test)-1>::result};
};

struct Test
{
    int a;
    double b;
    double c;
};

int main()
{
    std::cout << sizeof(Test) << " -> " << Calc<Test>::size << std::endl;
    return 0;
}

Тогда значение заполнения должно быть простым.

1
ответ дан 3 December 2019 в 13:56
поделиться
union Message
{
    struct
    {
        unsigned long member1;
        unsigned long member2; //...
    };
    char pad[1 << 5]; //change 5 to whatever size you need...
};

Было бы немного чище.

0
ответ дан 3 December 2019 в 13:56
поделиться

Мне нравится ответ Ники , особенно часть с анонимными структурами.

Единственное, что не удалось решить, - это проблема с размером более 64 байтов, но это можно решить, условно объявив элемент структуры char

if sizeof (long) == 8 и объявив char [64] в противном случае.

0
ответ дан 3 December 2019 в 13:56
поделиться

Хорошо, я нашел ответ, который действительно искал. По сути, вам нужно вызвать LocalFileSettingsProvider.Upgrade. Однако, поскольку я буду развертывать с помощью ClickOnce, он сделает это за вас автоматически.


Q: Хорошо, но как мне узнать, когда вызывать Upgrade?

A: Хороший вопрос. В Clickonce, когда вы устанавливаете новую версию своего приложения, ApplicationSettingsBase обнаружит ее и автоматически обновит настройки для вас в момент загрузки настроек. В случаях, не связанных с Clickonce, автоматическое обновление отсутствует - вам нужно вызвать обновление самостоятельно. Вот одна идея для определения, когда вызывать Upgrade:

Имейте логическую настройку CallUpgrade и присвойте ей значение по умолчанию true. Когда ваше приложение запустится, вы можете сделать что-то вроде:

0
ответ дан 3 December 2019 в 13:56
поделиться
Другие вопросы по тегам:

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