使用-1初始化struct或array的无符号in {}初始化

Kra*_*lew 14 c c++ initialization narrowing c++11

非常简短

如何创建一个包含所有位的无符号常量?

...您可以使用{} 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
Run Code Online (Sandbox Code Playgroud)

基本上,用户,即编写{}初始化的人,不知道ufield的类型.他只知道它是一个无符号类型,但不知道它有多宽.它不完全是无符号类型.

*另一个原因我想要尽可能简单优雅的语法*

我不妨提一下其他内容:这里的"用户"实际上并不是在编写C或C++程序.他正在编辑配置文件.程序,简单的Perl或Python脚本,处理配置文件,并生成C代码.这个程序不是很复杂,目前通过看起来像的文本块

 Foo: {-1,2,3};
Run Code Online (Sandbox Code Playgroud)

生成typedef结构Some_Struct {unsigned a; 无符号b,无符号c; Some_Struct = {-1,2,3}; //同上

基本上,我希望能够为一个文字提供一个友好的用户友好语法,该文字说明"此无符号值中的所有位都已设置".无需知道有多大的无符号.并且没有处理配置文件的程序变得太复杂.

以免潜在的答案提供者抱怨这是一个新的约束,不现实等等:
我对模板有完全相同的问题.即模板类型,我想写一个"无符号宽度,全1"的文字.在模板我可能更愿意做一些丑陋的,丑陋的,丑陋的语法,显然是能够做到这一点的,但我真的希望能有一个简单,优雅,语法.

*真正的问题*

问:有没有办法在不触发GCC 4.7.2警告的情况下创建一个"全1设置"的常量?

简要

我遇到了一个使用文字常量-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);
}
Run Code Online (Sandbox Code Playgroud)

虽然早期版本的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]
Run Code Online (Sandbox Code Playgroud)

注意:这只是一个警告.将-1转换为无符号的结果在C/C++标准中得到了很好的定义:

> ./a.out
ustruct.ufield    = ffffffff
Run Code Online (Sandbox Code Playgroud)

我不喜欢警告,所以我想沉默这个恼人的警告.我不想使用适用于整个文件的#pragmas,因为这可能会禁用对真正错误的警告.

(顺便说一句,只有在初始化字段时才能获得此警告.而不是在初始化非字段时

unsigned u = -1;  // no cmpiler warning.
Run Code Online (Sandbox Code Playgroud)

struct U { unsigned ufield; } ustruct = { ~0U };
Run Code Online (Sandbox Code Playgroud)

沉默了.

但有人指出,如果字段的类型不是无符号的,而是uint64_t,则~0U提供的结果与-1:0x00000000FFFFFFFF不同,而不是0xFFFFFFFFFFFFFFFF.(即3位的32位,而不是1位的64位.)

struct U和initializaton代码可能存在于完全不同的地方,我们希望能够在不通知用户的情况下增加字段的大小,即位掩码.并且意图是获得所使用的无符号类型的"所有1的掩码".

同样

struct U { unsigned ufield; } ustruct = { -1u };
Run Code Online (Sandbox Code Playgroud)

沉默了.(令我惊讶的是 - 我不知道-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]
Run Code Online (Sandbox Code Playgroud)

在早期的编译器中不会发生:

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.
Run Code Online (Sandbox Code Playgroud)

asc*_*ler 6

一个稍微用户友好的@Ali的回答版本:

#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;
}
Run Code Online (Sandbox Code Playgroud)

根据您尝试转换为签名类型时想要发生的事情,您可以更改enable_if为允许所有整数类型,或者添加另一个带有nice的重载static_assert.