Использование -1 для инициализации без знака в {} инициализации структуры или массива

ДЕЙСТВИТЕЛЬНО КРАТКИЙ

Как создать константу без знака, в которой установлены все биты?

…что вы можете использовать для инициализации поля с {} s,

…это не получает предупреждение о сужении от GCC 4.7.2.

Следующее не является удовлетворительным:

 struct U { unsigned ufield; };
struct Uc { unsigned char ufield; };
struct ULL { unsigned long long ufield; };
struct U32 { unsigned ufield; };
struct U64 { uint64_t ufield; }

typedef
//any of the above U Uc ULL U32 U64, we will arbitrarily choose:
U Ueg;// somewhere far away
Ueg u = {-1};   // well defined by C standard, GCC 4.7.2 -Wnarrowing warning
Ueg u = {~0U};  // finit width constant, warnings in some places, silent non-all-1s-mask others
Ueg u = {~0ULL};  // ditto
Ueg u = {-1ULL};  // ditto

По сути, пользователь, парень, пишущий инициализацию {},
не знает тип поля.
Он знает только, что это тип без знака, но не как широко.
Не совсем какой тип без знака это.

* Еще одна причина, почему я хочу максимально простой и элегантный синтаксис *

Я мог бы также упомянуть кое-что еще: «пользователь» здесь фактически не пишет программу на C или C ++.
Он редактирует файл конфигурации.
Программа, простой скрипт на Perl или Python, обрабатывает файл конфигурации и генерирует C-код.
Эта программа не очень сложна, и в данный момент проходит через куски текста, которые выглядят как

 Foo: {-1,2,3};

чтобы генерировать
ЬурейеЕ
struct Some_Struct {unsigned a; без знака b, без знака c; }
Some_Struct = {-1,2,3}; // то же самое

По сути, я хочу иметь удобный синтаксис для литерала, который говорит
Msgstr «Все биты в этом значении без знака установлены».
Без необходимости знать, какой большой из неподписанных.
И без программы, которая обрабатывает файл конфигурации, становится слишком сложным.

Чтобы потенциальный поставщик ответов не пожаловался, что это новое ограничение, нереалистичное и т. Д.
У меня была точно такая же проблема с шаблонами.
То есть с типами шаблонов, где я хочу написать литерал, который «без знака любой ширины, все 1 с».
В шаблоне я мог бы быть более склонен к использованию некрасивого синтаксиса Ugly, UGLY.
что, очевидно, может сделать это:
но мне бы очень хотелось, чтобы был простой, элегантный синтаксис.

* Настоящий вопрос *

Вопрос: есть ли способ создать константу, для которой установлено «все 1», без предупреждения GCC 4.7.2?

КРАТКАЯ

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

> cat ./-1u.cpp
#include <stdio.h>

struct U { unsigned ufield; } ustruct = { -1 };

int main(int argc, char** argv)
{
printf("ustruct.ufield    = %08x\n",ustruct.ufield);
}

Хотя более ранние версии GCC приняли это без предупреждения,
относительно недавняя версия GCC 4.7.2 содержит предупреждение:

> /SOME-PATH/import/gcc/gcc-4.7.2.pkg/installdir/bin/g++ -Wall ./-1u.cpp
./-1u.cpp:3:46: warning: narrowing conversion of '-1' from 'int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]

Примечание: это только предупреждение. Результат преобразования -1 в unsigned хорошо определен в стандартах C / C ++:

> ./a.out
ustruct.ufield    = ffffffff

Мне не нравятся предупреждения, поэтому я хотел бы заставить замолчать это раздражающее предупреждение. Я предпочитаю не использовать #pragmas, которые применяются ко всему файлу, так как это может отключить предупреждение для реальных ошибок.

(Кстати, вы получаете это предупреждение только при инициализации поля. Не при инициализации неполя

unsigned u = -1;  // no cmpiler warning.

дела

struct U { unsigned ufield; } ustruct = { ~0U };

заставляет замолчать ошибку.

Но было отмечено, что если тип поля не без знака, а вместо этого uint64_t,
тогда ~ 0U дает результат, отличный от -1: 0x00000000FFFFFFFF, а не 0xFFFFFFFFFFFFFFFF.
(Т.е. 32 бита 1 с, а не 64 бита 1 с.)

Структура U и код инициализации могут жить в совершенно разных местах,
и мы хотели бы иметь возможность увеличить размер поля, немного маскируя, не информируя пользователей.
И цель состоит в том, чтобы получить «маску всех 1» любого типа без знака.

так же

struct U { unsigned ufield; } ustruct = { -1u };

заставляет замолчать ошибку. (К моему удивлению — я не знал, что -1 может считаться незамеченным.)

Но также является постоянной конечной ширины.

ДЕТАЛЬ

Вот тестовая программа.
(Кстати, все, о чем я спрашиваю, это использование литеральной константы со знаком -1
инициализировать неподписанного члена. Другие предупреждения — просто тесты.
Вам не нужно объяснять мне, что 64-разрядное число не умещается в 32-разрядное.)

sh-3.2$ cat ./-1u.cpp

#include <stdio.h>

unsigned um1 = -1;

unsigned un0u = ~0u;

unsigned un0ull = ~0ull;

struct Foo {
unsigned um1;
unsigned un0u;
unsigned un0ull;
};

Foo foo = { -1, ~0u, ~0ull };int main(int argc, char** argv)
{
printf("um1    = %08x\n",um1);
printf("un0u   = %08x\n",un0u);
printf("un0ull = %08x\n",un0ull);

printf("foo.um1    = %08x\n",foo.um1);
printf("foo.un0u   = %08x\n",foo.un0u);
printf("foo.un0ull = %08x\n",foo.un0ull);
}

sh-3.2$ /mips/proj/performance/import/gcc/gcc-4.7.2.pkg/installdir/bin/gcc -Wall ./-1u.cpp
./-1u.cpp:7:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
./-1u.cpp:15:28: warning: narrowing conversion of '-1' from 'int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:28: warning: narrowing conversion of '18446744073709551615ull' from 'long long unsigned int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:28: warning: large integer implicitly truncated to unsigned type [-Woverflow]

sh-3.2$ /mips/proj/performance/import/gcc/gcc-4.7.2.pkg/installdir/bin/g++ -Wall ./-1u.cpp
./-1u.cpp:7:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
./-1u.cpp:15:35: warning: narrowing conversion of '-1' from 'int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:35: warning: narrowing conversion of '18446744073709551615ull' from 'long long unsigned int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:35: warning: large integer implicitly truncated to unsigned type [-Woverflow]

Не встречается в более раннем компиляторе:

sh-3.2$ /usr/bin/g++ -Wall ./-1u.cpp
./-1u.cpp:7: warning: large integer implicitly truncated to unsigned type
./-1u.cpp:15: warning: large integer implicitly truncated to unsigned type

/usr/bin/g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-51)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

14

Решение

Чуть более удобная версия ответа @ Али:

#include <type_traits>

struct all_ones_type {
template <typename T,
typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
constexpr operator T () const
{ return static_cast<T>(-1); }
} const all_ones;

#include <iostream>

struct X {
unsigned short a;
unsigned long b;
unsigned long long c;
};

int main() {
X x = { all_ones, all_ones, all_ones };
std::cout << x.a << "\n"<< x.b << "\n"<< x.c << std::endl;
}

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

6

Другие решения

Как насчет этого? Это работает только для неподписанных типов, но вопрос конкретно говорит без знака. (См. Комментарии rubenvb ниже.)

#include <cinttypes>
#include <iomanip>
#include <iostream>
#include <limits>
#include <type_traits>

template <typename T>
T all_bits_one() {
static_assert(std::is_unsigned<T>::value, "the type must be unsigned");
return std::numeric_limits<T>::max();
}

struct Ui {
typedef unsigned int the_type;
the_type ufield;
};

struct ULL {
typedef unsigned long long the_type;
the_type ufield;
};

struct U64 {
typedef uint64_t the_type;
the_type ufield;
};

int main() {

using namespace std;

Ui  ui  = { all_bits_one< Ui::the_type>() };
ULL ull = { all_bits_one<ULL::the_type>() };
U64 u64 = { all_bits_one<U64::the_type>() };

cout << hex;
cout << "unsigned int:       " <<  ui.ufield << endl;
cout << "unsigned long long: " << ull.ufield << endl;
cout << "unsigned int 64:    " << u64.ufield << endl;

//all_bits_one<int>(); // causes compile-time error if uncommented

return 0;
}

Пользователь не должен знать точный тип the_type или количество битов, на которых оно представлено.

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

Я думаю, вы упростили свой код перед публикацией. Как оно есть, ваш structне имеет смысла для меня, простой typedef было бы достаточно.

3

Почему бы не предоставить маску вместе с типом?

C:

 struct U { unsigned ufield; };
#define U_MASK (-1U)

// somewhere far away
U u = {U_MASK};

C ++:

struct U { unsigned ufield; static constexpr unsigned MASK = -1; };

// somewhere far away
U u = {U::MASK};
2

Если оставить в стороне весь модный код шаблона, вот немного модного кода C ++ 11:

struct Foo
{
unsigned a;
unsigned long b;
unsigned long long c;
};

Foo foo = { decltype(Foo::a)(-1), decltype(Foo::b)(-1), decltype(Foo::c)(-1) };

который подвержен ошибкам, но функционален.

Лучшее решение по-прежнему использовать (напечатано) enum (class) за это.

1

По-другому

// C++03 and C++11
Ueg u = { (Ueg().ufield - 1) };

// C99 and C11 (works only inside of functions)
Ueg u = { (Ueg){0}.ufield - 1 };
1

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

T all_bits_one(T& dummy) { return ~(T()); }
unsigned long u = all_bits_one(u);
1

Может быть, то, что вы хотите, инициализируя uint -1, это то, что все биты установлены в «1»?
В таком случае:

typedef uint MyUIntType;
MyUIntType mID = (MyUIntType)~0;

~ применяет «1 дополнение» к 0 который эффективно переворачивает все свои биты.
Результатом будет наибольшее значение, которое может содержать ваш тип uint, что полезно в случаях, когда 0 является значимым значением, а переменные необходимо инициализировать как «что-то еще».

0
По вопросам рекламы [email protected]