2012-03-26 5 views
0

У меня есть проблема, которую я не могу решить. Скажем, у меня есть такое определение карты:Основы определения языка C++

map<string, int16_t> Registers; 

, но иногда, мне нужно хранить без знака int16_t вместо подписанного int16_t. Как я могу это сделать?

Спасибо.

+0

Вы пытались использовать 'uint16_t' в качестве второго типа шаблона для контейнера, в который собираетесь хранить неподписанные ints? – Alexander

+0

Привет, Александр, я не знал, что ты можешь это сделать. – Kam

+0

@ Александр: Что именно вы имеете в виду? Может быть, дать пример объявления? –

ответ

5

Вы можете использовать более крупную рыбу , например int32_t, или использовать boost::variant.

int32_t может хранить все значения, что int16_t или uint16_t может, и сохраняет разницу между, например, 32768 и -32768 (предполагается, что в дополнительном коде). Если вы использовали какую-то схему литья с int16_t и uint16_t, разница между ними будет потеряна, так как оба будут сохранены как 0x8000. При расчете таких значений, как 0x8000, потребуется внеполосная информация, которая, если есть, вы не упомянули.

Однако int32_t не сохранит разницу между 32767 и 32767 без знака. Если это имеет значение, то boost::variant может сохранить эту информацию.

+0

lol для вычеркивание sehe

+0

Привет, ну, допустим, у меня есть: map Регистры; тогда, если я сохраню 16-битное значение, которое должно было быть беззнаковым, тогда какая польза? Я имею в виду, если у меня есть int16_t, тогда, если я знаю, что значение без знака, я просто его бросил? нет? Я не вижу смысла использовать 32-битный int – Kam

+0

@Kam. Все 16-битные значения, подписанные или неподписанные, будут вписываться в 'int32_t'. –

3

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

Существует несколько способов, например. варианты.

Одной из возможностей является:

class Foo { 
public: 
    enum class Type : char { Int16, Uint16 }; 

    static Foo Int16 (int v)   { Foo ret{Type::Int16}; ret.int16_ = v; return ret;} 
    static Foo Uint16 (unsigned int v) { Foo ret{Type::Uint16}; ret.uint16_ = v; return ret;} 

    int16_t as_int16() const { assert_(Type::Int16); return int16_; } 
    uint16_t as_uint16() const { assert_(Type::Uint16); return uint16_; } 

    Type type() const { return type_; } 

private: 
    Foo (Type type) : type_(type) {} 
    void assert_(Type t) const { if (t != type_) throw "meh"; } 

    union { int16_t int16_; uint16_t uint16_; }; 
    Type type_; 
}; 

Пример:

int main() { 
    Foo f = Foo::Int16(4); 
    std::cout << f.as_int16() << '\n'; // okay 
    //std::cout << f.as_uint16() << '\n'; // exception 

    Foo g = Foo::Uint16(4); 
    std::cout << f.as_uint16() << '\n'; // okay 
    //std::cout << f.as_int16() << '\n'; // exception 

    // Switch on its type: 
    switch (g.type()) 
    { 
    Foo::Type::Int16: std::cout << g.as_int() << '\n'; break; 
    Foo::Type::Uint16: std::cout << g.as_uint() << '\n'; break; 
    } 
} 

Это в основном union, что будет сгенерировано исключение при попытке чтения int, но на самом деле хранится unsigned int; Kinda union, который был сделан трудно применимым-неправильным.

boost::variant будет другой вариант.

Третий вариант, как уже упоминал Р. Мартиньо Фернандес, заключался бы в использовании большего, подписанного int. Это зависит от вашего прецедента, может ли быть неправильным, если вы хотите разрешить хранить T, а затем читать как U, если вам нравятся посетители, если вам нужно отслеживать тип вообще, и так далее.

Мое сохранение, отслеживание решения в моей системе на 4 байта (из-за выравнивания), как и большее целое число со знаком. Я думаю, потому что вы храните свои значения в контейнере, не удастся пропустить отслеживание типа, оставив 2 байта, поэтому, я думаю, ваш минимум составляет 4 байта в любом случае.

+0

phresnel, я такой новичок, я постараюсь понять, что вы только что написали, и вернуться к вам. Спасибо – Kam

+0

Я думаю, что это может победить намерение акита сохранить 16-битное число. Если повторно использовать 16-битные типы, это будет размер int + 2 на большинстве pc-платформ, потому что многие перечисления хранятся в int. Использование 4-байтного типа подписки (int/long в большинстве мест) было бы лучше во многих отношениях. Если вы использовали bool для хранения независимо от того, подписали ли это и переработали ли он, чтобы использовать 16-битные типы, вы можете получить его до 3 байтов на экземпляр. – Sqeaky

+0

@Sqeaky: Но из-за выравнивания он снова поднялся бы до 4. Я буду использовать новую явную типизацию перечисления C++ 11. –

0

Либо вы вводите 1 уровень косвенности (теряете всю точку хранения int16_t в значительной степени), либо вам нужно 2 разных карты. Если вы не нацеливаете специализированное оборудование или вам не нужно экономить пространство, вам лучше хранить прямой int. Это будет быстрее и меньше хлопот в целом.

0

Учитывая, что два типа имеют одинаковый размер, вы можете использовать unsigned int as и int. Просто убедитесь, что вы отслеживаете погоду, когда ваше значение подписано или не подписано, что может означать, что лучше использовать более крупный тип, поэтому вам не нужно отслеживать его подписку.

Смежные вопросы