【问题标题】:How to initialize char array using hex numbers?如何使用十六进制数字初始化 char 数组?
【发布时间】:2013-11-11 23:39:07
【问题描述】:

我使用 utf8 并且必须在 char 数组中保存一个常量:

const char s[] = {0xE2,0x82,0xAC, 0}; //the euro sign

但是它给了我错误:

test.cpp:15:40: error: narrowing conversion of ‘226’ from ‘int’ to ‘const char’ inside { } [-fpermissive]

我必须将所有十六进制数字转换为 char,我觉得这很乏味,而且味道不好。还有其他合适的方法吗?

【问题讨论】:

  • @AaronMcDaid 看看我的第一句话?
  • 为什么不const char s[] = u8"\u20AC";
  • 正如@KerrekSB 提到的,但它是一个 c++11 功能。

标签: c++ unicode


【解决方案1】:

char 可能是signedunsigned(默认值是特定于实现的)。你可能想要

  const unsigned char s[] = {0xE2,0x82,0xAC, 0}; 

  const char s[] = "\xe2\x82\xac";

或使用许多最近的编译器(包括GCC

  const char s[] = "€";

string literalchar 的数组,除非你给它一些前缀)

参见 GCC 的-funsigned-char(或-fsigned-char)选项。

在某些实现中,charunsignedCHAR_MAX 是 255(而 CHAR_MIN 是 0)。在其他人char-s 是signed 所以CHAR_MIN 是-128 而CHAR_MAX 是127(例如,Linux/PowerPC/32 位和 Linux/x86/32 位的情况不同)。 AFAIK 标准中没有任何内容禁止 19 位有符号字符。

【讨论】:

  • @John 如果您没有指定 char 的签名,则您使用的是编译器的默认值......这可以(并且很可能会)在不同的编译器供应商(甚至不同版本的相同的编译器)。当您需要 char 成为 byte 时,您应该将其声明为这样(并且不要假设编译器可能会或可能不会做什么。
  • @BasileStarynkevitch:是的,就在几天前,我在标准的深处花了很长时间来弄清楚为什么我的代码不起作用,我发现了这个宝石,我从中意识到我需要三个重载,而不是两个。来自 C++03 的参考:3.9.1 基本类型“1/ [...] Plain char、signed char 和 unsigned char 是三种不同的类型。[...]”
  • @ZacHowland:同样的子句继续说,“在任何特定的实现中,一个普通的 char 对象可以采用与有符号字符或无符号字符相同的值;哪一个是实现——定义。”所以charsigned charunsigned char 不同,但它们在基本层面上是如此接近,以至于在 15 年的专业 C++ 编程中,我只需要区分它们一次 .
  • 只是我个人的看法,但从文体的角度来看,如果是文字,请使用char。我过去曾尝试使用unsigned char(因为我经常需要处理重音字符):它只是不起作用(因为很多函数都需要char*std::string,而字符串文字是@987654350 @),这让读者感到困惑。
  • @ZacHowland:我预测两年后你将不得不为某些东西编写第三个重载。但是你会再好15年。 :)
【解决方案2】:

对您的问题的简短回答是您溢出了charchar 的范围为 [-128, 127]。 0xE2 = 226 > 127。您需要使用的是unsigned char,其范围为[0, 255]。

unsigned char s = {0xE2,0x82,0xAC, 0};

【讨论】:

  • 那么默认情况下如果没有说明符,一个char是有符号的?
  • 不,在某些实现中,char 是无符号的,CHAR_MAX 是 255(而 CHAR_MIN 是 0)。在其他人charsigned 所以CHAR_MIN 是-128 而CHAR_MAX 是127(例如,Linux/PowerPC/32 位和 Linux/x86/32 位的情况不同)。
  • @texasbruce 这取决于编译器。在许多编译器上,默认值为signed。如果您需要unsigned,则应始终明确指定它。
【解决方案3】:

虽然在您的代码中添加大量强制转换可能很乏味,但对我来说,使用尽可能强的类型实际上感觉非常好。

如上所述,当您指定类型“char”时,您是在邀请编译器选择编译器编写者喜欢的任何内容(有符号或无符号)。我不是 UTF-8 方面的专家,但如果您不需要,没有理由让您的代码不可移植。

就您的常量而言,我使用了将默认常量以这种方式写入有符号整数的编译器,以及考虑上下文并相应解释它们的编译器。请注意,有符号和无符号之间的转换可能会溢出。对于相同的位数,负数会溢出无符号(显然),并且设置了最高位的无符号会溢出有符号,因为最高位表示负数。

在这种情况下,您的编译器将您的常量视为无符号 8 位 - 或更大 - 这意味着它们不适合作为有符号 8 位。我们都感谢编译器抱怨(至少我是)。

我的观点是,通过选角来准确展示您打算发生的事情并没有什么不好。如果编译器允许您在有符号和无符号之间进行分配,则它应该要求您进行强制转换,而不考虑变量或常量。例如

const int8_t a = (int8_t) 0xFF; // 将是 -1

虽然在我的示例中,分配 -1 会更好。当您必须添加额外的强制转换时,它们要么有意义,要么您应该对常量进行编码,以便它们对您分配的类型有意义。

【讨论】:

  • 虽然更强的类型检查可能有助于发现错误,但它对必须处理遗留代码的项目造成了很大的伤害。从跨越 0x00-0xFF 的十六进制常量初始化 char 数组是很常见的,例如:X Bitmap (XBM) file format(它实际上是 C 源代码的 sn-p,具有精确的这种初始化),以及许多 X 库函数处理带有渐变、颜色映射等,它们需要 chars 的数组,而不是 unsigned chars 的数组。
【解决方案4】:

有没有办法混合这些?我想要一个定义宏FX_RGB(R,G,B),它会生成一个常量字符串“\x01\xRR\xGG\xBB”,所以我可以执行以下操作: const char* LED_text = "Hello " FX_RGB(0xff, 0xff, 0x80) "World"; 并得到一个刺痛:const char* LED_text = "Hello \x01\xff\xff\x80World";

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-22
    • 2012-03-03
    • 1970-01-01
    • 2016-02-01
    • 2012-07-27
    • 2013-11-25
    • 2014-02-09
    相关资源
    最近更新 更多