C++ 如何将字符数组转换为单个整数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4633252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:00:26  来源:igfitidea点击:

how to cast an array of char into a single integer number?

c++pngintegercharcasting

提问by sepisoad

i'm trying to read contents of PNG file.

我正在尝试读取 PNG 文件的内容。

As you may know, all data is written in a 4-byte manner in png files, both text and numbers. so if we have number 35234 it is save in this way: [1000][1001][1010][0010].

您可能知道,所有数据都以 4 字节的方式写入 png 文件,包括文本和数字。所以如果我们有数字 35234,它会以这种方式保存:[1000][1001][1010][0010]。

but sometimes numbers are shorter, so the first bytes are zero, and when I read the array and cast it from char* to integer I get wrong number. for example [0000] [0000] [0001] [1011] sometimes numbers are misinterpreted as negative numbers and simetimes as zero!

但有时数字更短,所以第一个字节为零,当我读取数组并将其从 char* 转换为整数时,我得到了错误的数字。例如 [0000] [0000] [0001] [1011] 有时数字被误解为负数,有时被误解为零!

let me give you an intuitive example:

让我给你一个直观的例子:

char s_num[4] = {120, 80, 40, 1};

int  t_num = 0;

t_num = int(s_num);

I wish I could explain my problem well!

我希望我能很好地解释我的问题!

how can i cast such arrays into a single integer value?

如何将此类数组转换为单个整数值?

ok ok ok, let me change my code to explain it better:

好吧好吧,让我更改我的代码以更好地解释它:

char s_num[4] = {0, 0, 0, 13};
int  t_num;


t_num = *((int*) s_num);
cout << "t_num: " << t_num << endl;

here we have to get 13 as the result, ok? but again with this new solution the answer is wrong, you can test on your computers! i get this number:218103808 which is definitely wrong!

这里我们必须得到 13 作为结果,好吗?但是再次使用这个新解决方案,答案是错误的,您可以在您的计算机上进行测试!我得到这个号码:218103808 这绝对是错误的!

回答by Axel

You cast (char*) to (int). What you should do is cast to pointer to integer, i.e.

您将 (char*) 转换为 (int)。你应该做的是转换为指向整数的指针,即

t_num = *((int*) s_num));

But really you should extract your code into it's own function and make sure that:

但实际上您应该将代码提取到它自己的函数中并确保:

  1. endianness is correct
  2. sizeof(int) == 4
  3. Use C++ casts (i.e. static, dynamic, const, reinterpret)
  1. 字节序是正确的
  2. sizeof(int) == 4
  3. 使用 C++ 强制转换(即static, dynamic, const, reinterpret

回答by Eli Bendersky

Assuming a little-endian machine with a 32-bit integer, you can do:

假设有一个 32 位整数的小端机器,你可以这样做:

char s_num[4] = {0xAF, 0x50, 0x28, 0x1};
int t_num = *((int*)s_num);

To break it into steps:

把它分成几个步骤:

  1. s_numis an array, which can be interpreted as a pointer to its first element (char*here)
  2. Cast s_numto int*because of (1) - it's OK to cast pointers
  3. Access the integer pointed to by the cast pointer (dereference)
  1. s_num是一个数组,可以解释为指向其第一个元素的指针(char*此处)
  2. 投射s_numint*因为 (1) - 可以投射指针
  3. 访问转换指针指向的整数(解引用)

To have 0xAFas the low byte of the integer. Fuller example (C code):

若要0xAF为整数的低字节。完整示例(C 代码):

#include <stdio.h>

int main()
{
    char s_num[4] = {0xAF, 0x50, 0x28, 0x1};
    int t_num = *((int*)s_num);

    printf("%x\n", t_num);
    return 0;
} 

Prints:

印刷:

12850af

As expected.

正如预期的那样。

Note that this method isn't too portable, as it assumes endianness and integer size. If you have a simple task to perform on a single machine you may get away with it, but for something production quality you'll have to take portability into account.

请注意,此方法不太便携,因为它假定字节序和整数大小。如果您有一个简单的任务要在一台机器上执行,您可能会侥幸成功,但对于生产质量,您必须考虑便携性。

Also, in C++ code it would be better to use reinterpret_castinstead of the C-style cast.

此外,在 C++ 代码中最好使用reinterpret_cast而不是 C 风格的强制转换。

回答by Tom

I find using the std bitset the most explicit way of doing conversions (In particular debugging.)

我发现使用 std bitset 是进行转换的最明确的方式(特别是调试。)

The following perhaps is not what you want in your final code (too verbose maybe) - but I find it great for trying to understand exactly what is going on.

以下内容可能不是您想要的最终代码(可能太冗长)-但我发现它非常适合尝试准确了解正在发生的事情。

http://www.cplusplus.com/reference/stl/bitset/

http://www.cplusplus.com/reference/stl/bitset/

#include <bitset>
#include <iostream>
#include <string>

int
main  (int ac, char **av)
{

  char s_num[4] = {120, 80, 40, 1};
  std::bitset<8> zeroth   = s_num[0];
  std::bitset<8> first    = s_num[1];
  std::bitset<8> second   = s_num[2];
  std::bitset<8> third    = s_num[3];

  std::bitset<32> combo;
  for(size_t i=0;i<8;++i){
    combo[i]     = zeroth[i];
    combo[i+8]   = first[i];
    combo[i+16]  = second[i];
    combo[i+24]  = third[i];
  }
  for(size_t i = 0; i<32; ++i)
    {
      std::cout<<"bits ["<<i<<"] ="<<combo.test(i)<<std::endl;
    }
  std::cout<<"int = "<<combo.to_ulong()<<std::endl;
}

回答by xskxzr

Axel's answer violates the strict aliasing rule, at least since C++14. So I post this answer for future users.

Axel 的回答违反了严格的别名规则,至少从 C++14 开始。所以我为未来的用户发布了这个答案。



Apart from endianness and size issues, a safe way is to use std::memcpy, i.e.

除了字节序和大小问题,一个安全的方法是使用std::memcpy,即

   unsigned char s_num[4] = {13, 0, 0, 0}; 
// ^^^^^^^^               // ^^ fix endianness issue
// use unsigned char to avoid potential issues caused by sign bit

int t_num;

std::memcpy(&t_num, s_num, 4);

回答by Maciej

Conversion is done good, because you aren't summing up these values but assign them as one value. If you want to sum them you have to do it manualy:

转换做得很好,因为您不是将这些值相加,而是将它们分配为一个值。如果你想对它们求和,你必须手动完成:

int i;
for (i = 0; i<4; ++i)
    t_num += s_num[i];

回答by Philip Potter

EDIT: it seems that you don't want to sum the numbers after all. Leaving this answer here for posterity, but it likely doesn't answer the question you want to ask.

编辑:看来您毕竟不想对数字求和。将此答案留在这里供后代使用,但它可能无法回答您想问的问题。

You want to sum the values up, so use std::accumulate:

你想总结这些值,所以使用std::accumulate

#include <numeric>
#include <iostream>

int main(void) {
    char s_num[4] = {120,80,40,1};
    std::cout << std::accumulate(s_num, s_num+4,0) << std::endl;
    return 0;
}

Produces output:

产生输出:

pgp@axel02:~/tmp$ g++ -ansi -pedantic -W -Wall foo.cpp -ofoo
pgp@axel02:~/tmp$ ./foo
241

回答by jmort253

Did you know that int's in C++ overflow after the 32767'th value? That would explain your negative number for 35234.

您是否知道 C++ 中的 int 在第 32767 个值之后溢出?这可以解释您的负数 35234。

The solution is to use a data type that can handle the larger values. See the Integer Overflow article for more information:

解决方案是使用可以处理较大值的数据类型。有关更多信息,请参阅整数溢出文章:

http://en.wikipedia.org/wiki/Integer_overflow

http://en.wikipedia.org/wiki/Integer_overflow

UPDATE: I wrote this not thinking that we all live in the modern world where 32 bit and 64 bit machines exist and flourish!! The overflow for int's is in fact much much larger than my original statement.

更新:我写这篇文章并不是想着我们都生活在 32 位和 64 位机器存在并蓬勃发展的现代世界中!!int 的溢出实际上比我原来的声明大得多。