C++ 将二维数组重新解释为指针

C++ 将二维数组重新解释为指针,c++,arrays,pointers,C++,Arrays,Pointers,假设我有这样一个数组: unsigned char a[10][10]; 我想使用fread将字节读入这个数组(行主顺序): 由于fread的第一个参数类型为void*,是否有标准方法将无符号字符a[10][10]转换为void*?我应该使用static\u cast还是reinterpret\u cast或?当C++中的2D数组连续分配时,我认为重新解释它为指针是合理的。 < P>以下工作在GCC 4.82: FILE *f = fopen("xxx.bin", "rb"); fread(a

假设我有这样一个数组:

unsigned char a[10][10];
我想使用fread将字节读入这个数组(行主顺序):


由于fread的第一个参数类型为
void*
,是否有标准方法将
无符号字符a[10][10]
转换为
void*
?我应该使用
static\u cast
还是
reinterpret\u cast
或?当C++中的2D数组连续分配时,我认为重新解释它为指针是合理的。

< P>以下工作在GCC 4.82:

FILE *f = fopen("xxx.bin", "rb");
fread(a, sizeof(unsigned char), 10 * 10, f);
fclose(f);
如果您喜欢显式强制转换,那么标准的方法是使用
静态\u强制转换
。应该使用它,因为它在强制转换为
void*
时保留地址

FILE *f = fopen("xxx.bin", "rb");
fread(static_cast<void*>(a), sizeof(unsigned char), 10 * 10, f);
fclose(f);
FILE*f=fopen(“xxx.bin”、“rb”);
fread(static_cast(a),sizeof(unsigned char),10*10,f);
fclose(f);

reinterpret\u cast
仅保证,如果您将某个内容强制转换为
void*
,然后再强制转换回您的类型,则您将获得相同的值。

gcc 4.8.2中的以下内容适用:

FILE *f = fopen("xxx.bin", "rb");
fread(a, sizeof(unsigned char), 10 * 10, f);
fclose(f);
如果您喜欢显式强制转换,那么标准的方法是使用
静态\u强制转换
。应该使用它,因为它在强制转换为
void*
时保留地址

FILE *f = fopen("xxx.bin", "rb");
fread(static_cast<void*>(a), sizeof(unsigned char), 10 * 10, f);
fclose(f);
FILE*f=fopen(“xxx.bin”、“rb”);
fread(static_cast(a),sizeof(unsigned char),10*10,f);
fclose(f);

reinterpret\u cast
仅保证,如果您将某个内容强制转换为
void*
,然后再强制转换回您的类型,那么您将获得相同的值。

要获得指向
a
void*
,只需获取其地址(
&a
)并让编译器执行到
void*
的隐式转换:

fread(&a, sizeof a, 1, f);
这里有一些注意事项:

  • 首先,您很费力地关闭了文件,但没有检查读取错误
  • 无论何时使用reinterpret_cast,使用结果的唯一方法是将其重新解释为前一种类型。因此,通常不使用reinterpret_cast,除非需要将指针存储在整数中。正如其他人所提到的那样,静态_cast是一条路要走
  • 切勿使用C型铸造。他们是危险的,他们根本不记录正在发生的事情。FWIW,你可以const修饰你的数组,你的代码会在运行时愉快地编译和中断,因为你覆盖了编译器的安全开关
  • 我不会指望矩阵的行之间没有填充,也就是说,它的大小不会只有100。您只能对每一行使用单独的读取操作来解决这个问题。我不确定这一点,虽然,它很可能是它的大小是保证不包括任何填充

为了获得指向
a
void*
,只需获取其地址(
&a
),并让编译器执行到
void*
的隐式转换:

fread(&a, sizeof a, 1, f);
这里有一些注意事项:

  • 首先,您很费力地关闭了文件,但没有检查读取错误
  • 无论何时使用reinterpret_cast,使用结果的唯一方法是将其重新解释为前一种类型。因此,通常不使用reinterpret_cast,除非需要将指针存储在整数中。正如其他人所提到的那样,静态_cast是一条路要走
  • 切勿使用C型铸造。他们是危险的,他们根本不记录正在发生的事情。FWIW,你可以const修饰你的数组,你的代码会在运行时愉快地编译和中断,因为你覆盖了编译器的安全开关
  • 我不会指望矩阵的行之间没有填充,也就是说,它的大小不会只有100。您只能对每一行使用单独的读取操作来解决这个问题。我不确定这一点,虽然,它很可能是它的大小是保证不包括任何填充

std::fread(a,sizeof(*a),sizeof(a)/sizeof(*a),f)如果您对一次读取这些行感兴趣,并且有可能出现子行失败(您确实应该通过检查返回结果来验证)。不知道为什么要用C API来实现这一点,但每个API都有自己的功能。祝你好运。
std::fread(a,sizeof(*a),sizeof(a)/sizeof(*a),f)如果您对一次读取这些行感兴趣,并且有可能出现子行失败(您确实应该通过检查返回结果来验证)。不知道为什么要用C API来实现这一点,但每个API都有自己的功能。祝你好运。@cmaster从[cv]
T*
到[cv]
void*
的转换是隐式的。只是转换另一种方式不是。@cmaster从[cv]
T*
到[cv]
void*
的转换是隐式的。仅以另一种方式进行转换是不行的。数组保证没有paddinghanks。不允许填充是有意义的,但我不确定。几乎正确,但是如果<代码> A <代码>已经是一个数组(1D,或2D或…)要小心:在C或C++中,数组已经是指针。因此,在示例中,正确的表达式是
fread(a,sizeof a,1,f)
&a
是一个
字符**
,数据将不会到达预期的位置@实际上不是。数组标识符在几乎所有上下文中都会衰减为指针,但它不是指针。这不仅仅是吹毛求疵,还有非常重要的后果。例如,这就是为什么
(intptr\t)a
(intptr\t)&a
a
是数组时具有相同值的原因。保证。@cmaster:谢谢你的精确性,我还以为我还在80年代的K&R C:-)。但是由于答案中没有明确的
a
,而且由于fread取了
void*
,编译器怎么能猜出我们希望
&a
fread(&a,sizeof(a),1,f)中是
a
?保证阵列没有填充线。不允许填充是有意义的,但我不确定。几乎正确,但是如果<代码> A <代码>已经是一个数组(1D,或2D或…)要小心:在C或C++中,一个数组已经存在。