Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 确保在编译时将数组填充到适当大小_C_Arrays - Fatal编程技术网

C 确保在编译时将数组填充到适当大小

C 确保在编译时将数组填充到适当大小,c,arrays,C,Arrays,如何确保在编译时将颜色名称填充到正确的大小?如果添加了一种新颜色,比如color_4(因此N_COLORS是自动递增的),编译器会告诉我color_名称没有按大小填充 我在网上找到的大多数答案都是针对运行时的,而不是针对编译时的 这是用于C风格的表示法(不使用STL和其他库) 理想的情况是能够使用来自预处理器的sizeof。但是我们不能,因为sizeof是由编译器计算的 有很多方法可以绕过这一点,但这里有一种非常简单且便于携带的方法: const char* COLOR_NAMES[] = {

如何确保在编译时将颜色名称填充到正确的大小?如果添加了一种新颜色,比如color_4(因此N_COLORS是自动递增的),编译器会告诉我color_名称没有按大小填充

我在网上找到的大多数答案都是针对运行时的,而不是针对编译时的

这是用于C风格的表示法(不使用STL和其他库)


理想的情况是能够使用来自预处理器的sizeof。但是我们不能,因为sizeof是由编译器计算的

有很多方法可以绕过这一点,但这里有一种非常简单且便于携带的方法:

const char* COLOR_NAMES[] = {
   /* COLOR_1 */ "Color1",
   /* COLOR_2 */ "Color2",
   /* COLOR_3 */ "Color3"
};

typedef char CHECK_COLOR_NAMES[sizeof(COLOR_NAMES) / sizeof(COLOR_NAMES[0]) == N_COLORS ? 1 : -1];
如果测试失败,您将尝试定义大小为-1的数组,这将导致编译错误


编辑:然后我们使用typedef来避免实际创建一个我们不会使用的变量(Lundin的评论)

对于这样的数组和相应的枚举,标准做法是将“枚举大小成员”
N_COLORS
与数组中的项数进行比较

要获得数组中的项数,只需将数组大小除以一个数组成员的大小即可

因此:

编辑:


哦,顺便说一句,要使其有意义,数组声明必须是
const char*COLOR\u NAMES[]=
,否则您将无法判断数组初始化列表中是否缺少初始值设定项。

对于constepxr,您可以使用:

constexpr static const char* COLOR_NAMES[N_COLORS] =
{
   /* COLOR_1 */ "Color1",
   /* COLOR_2 */ "Color2",
   /* COLOR_3 */ "Color3"
};

static_assert(COLOR_NAMES[N_COLORS-1] !=0);
如果要使用局部变量,可以使用variant

constexpr variant<const char*> COLOR_NAMES[N_COLORS] =
{
   /* COLOR_1 */ "Color1",
   /* COLOR_2 */ "Color2",
   /* COLOR_3 */ "Color3"
};

static_assert(get<0>(COLOR_NAMES[N_COLORS-1]) !=nullptr);
constexpr变体颜色名称[N\u颜色]=
{
/*颜色1*/“颜色1”,
/*颜色2*/“颜色2”,
/*颜色3*/“颜色3”
};
static_assert(get(COLOR_NAMES[N_COLORS-1])!=nullptr);

编译时间不太长,但您可以在单元测试中轻松检查这一点。如果可能的话,它如何知道新颜色使用什么字符串?上一个问题中“Sam”的答案看起来很聪明。创建“穷人的静态断言”时,最好使用
typedef
。这样,实际上就不会为无意义数组分配任何内存。更好的方法是:获得一个不超过5年的C编译器,这样你就有了对静态断言的语言支持。那么,用一秒钟的旧编译器进行静态断言的可移植方法是什么呢?谢谢。我认为仅仅在C11中存在静态断言就是升级到该标准的原因。旧的“无法在第666行声明大小为-1的数组”编译时断言错误不是很具有描述性:)啊,好的,谢谢!我一直对标准的静态断言保持沉默,因为VS(包括VS2015)根本不知道静态断言,并且通常忽略C11。但我刚刚了解到C11还定义了assert.h中的static_assert。在VS中,这是一个关键字,而不是assert.h:P中的宏。但这并不重要。因此,我认为当今理论与实践相结合的最佳方式是包含并使用静态断言,以实现最大的可移植性。再次感谢您:LN:这是因为VS主要是C++编译器,而 STATICOSAsReSt< <代码>是C++中的关键字。除了C++中的<代码>静态断言< /Cord>关键字外,它还包含了代码> StistaSytRe> <代码>作为宏,用于C++兼容性。C模式下的VS2015之所以不理解
\u Static\u assert
,是因为尽管名称中有2015,但它仍然是90年代中期的旧垃圾编译器。对于纯C编程,我会完全避免使用该编译器。如果COLOR_名称之外的内存空间一开始不是零会怎么样?@Ryuu根据以下链接:,如果T不是类(T数组[]),那么它的元素将不会初始化。但根据,静态变量将使用默认值初始化value@Ryuu对于局部变量,您可以将constexpr与variant一起使用,因为variant保证第一个元素将用默认值初始化。我从这里得到了这个想法:很酷的文章。谢谢
constexpr static const char* COLOR_NAMES[N_COLORS] =
{
   /* COLOR_1 */ "Color1",
   /* COLOR_2 */ "Color2",
   /* COLOR_3 */ "Color3"
};

static_assert(COLOR_NAMES[N_COLORS-1] !=0);
constexpr variant<const char*> COLOR_NAMES[N_COLORS] =
{
   /* COLOR_1 */ "Color1",
   /* COLOR_2 */ "Color2",
   /* COLOR_3 */ "Color3"
};

static_assert(get<0>(COLOR_NAMES[N_COLORS-1]) !=nullptr);