我的印象是访问union
除最后一个成员之外的成员是UB,但我似乎无法找到一个可靠的参考(除了声称它是UB但没有标准支持的答案).
那么,这是不确定的行为?
可能重复:
C宏定义确定大端或小端机器?
int main()
{
int x = 1;
char *y = (char*)&x;
printf("%c\n",*y+48);
}
Run Code Online (Sandbox Code Playgroud)
如果它是小端,它将打印1.如果它是大端,它将打印0.这是正确的吗?或者将char*设置为int x始终指向最低有效位,而不管字节顺序如何?
是否有一种安全,可移植的方法来确定(在编译期间)我的程序正在编译的平台的字节顺序?我在用C写作
[编辑]感谢您的回答,我决定坚持运行时解决方案!
(我想这个问题可能适用于许多类型语言,但我选择使用C++作为例子.)
为什么没有办法写:
struct foo {
little int x; // little-endian
big long int y; // big-endian
short z; // native endianness
};
Run Code Online (Sandbox Code Playgroud)
指定特定成员,变量和参数的字节顺序?
我知道变量的类型不仅决定了用于存储值的字节数,还决定了在执行计算时如何解释这些字节.
例如,这两个声明每个都分配一个字节,对于两个字节,每个可能的8位序列都是有效值:
signed char s;
unsigned char u;
Run Code Online (Sandbox Code Playgroud)
但是相同的二进制序列可能会有不同的解释,例如11111111
,在分配时指的是-1,而指定时指的是s
255 u
.当有符号和无符号变量涉及相同的计算时,编译器(主要)负责正确的转换.
在我的理解中,字节序只是同一原则的变体:基于关于存储它的存储器的编译时信息对二进制模式的不同解释.
在允许低级编程的类型语言中使用该功能似乎是显而易见的.但是,这不是C,C++或我所知的任何其他语言的一部分,我没有在网上找到任何关于此的讨论.
我会试着总结一下我在询问后的第一个小时内收到的许多评论中的一些内容:
此外,现在我意识到签名和字节序不是一个完美的类比,因为:
big int
并little int
会具有完全相同的数值范围.unsigned char
(假设char
有8位)130不能用a表示signed …
我有一些模板化的低级序列化代码,我需要在编译时明确知道系统的字节顺序(因为模板专门基于系统的字节顺序).
现在我有一个带有一些平台定义的标题,但是我宁愿通过一些模板化测试(如static_assert或boost_if)来做关于字节序的断言.原因是我的代码需要编译并在许多专业供应商的各种机器上运行,并且可能是2008年不存在的设备,因此我无法猜测可能需要进入标题年份的内容在路上.而且由于代码库的预期寿命约为10年.所以我无法永远遵循代码.
希望这能使我的情况变得清晰.
那么有没有人知道可以确定字节序的编译时测试,而不依赖于供应商特定的定义?
我正在研究一种以大端格式将64位值存储到内存中的函数.我希望我能编写可在小端和大端平台上运行的可移植C99代码,并让现代x86编译器bswap
自动生成指令而不需要任何内置函数或内在函数.所以我开始使用以下功能:
#include <stdint.h>
void
encode_bigend_u64(uint64_t value, void *vdest) {
uint64_t bigend;
uint8_t *bytes = (uint8_t*)&bigend;
bytes[0] = value >> 56;
bytes[1] = value >> 48;
bytes[2] = value >> 40;
bytes[3] = value >> 32;
bytes[4] = value >> 24;
bytes[5] = value >> 16;
bytes[6] = value >> 8;
bytes[7] = value;
uint64_t *dest = (uint64_t*)vdest;
*dest = bigend;
}
Run Code Online (Sandbox Code Playgroud)
这适用于clang,它将此函数编译为:
bswapq %rdi
movq %rdi, (%rsi)
retq
Run Code Online (Sandbox Code Playgroud)
但是GCC 无法检测到字节交换 …
我正在尝试创建一个C源代码,无论目标系统的字节顺序如何,它都能正确处理I/O.
我选择了"little endian"作为我的I/O约定,这意味着,对于大端CPU,我需要在写入或读取时转换数据.
转换不是问题.我面临的问题是检测字节序,最好是在编译时(因为CPU在执行过程中不会改变字节序...).
到目前为止,我一直在使用这个:
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
...
#else
...
#endif
Run Code Online (Sandbox Code Playgroud)
它被记录为GCC预定义的宏,而Visual似乎也理解它.
但是,我收到报告说某些big_endian系统(PowerPC)的检查失败了.
所以,我正在寻找一个万无一失的解决方案,确保无论编译器和目标系统如何都能正确检测到字节顺序.好吧,他们中的大多数至少......
[编辑]:提出的大多数解决方案都依赖于"运行时测试".编译期间编译器有时可以正确评估这些测试,因此不会产生实际的运行时性能.
然而,用某种<< if (0) { ... } else { ... }
>> 分支是不够的.在当前的代码实现中,变量和函数声明依赖于big_endian检测.使用if语句无法更改这些内容.
嗯,显然,有后备计划,即重写代码......
我宁愿避免这种情况,但是,它看起来像是一个越来越少的希望......
[编辑2]:我通过深度修改代码测试了"运行时测试".尽管他们正确地完成了工作,但这些测试也会影响性能.
我期待着,因为测试具有可预测的输出,编译器可以消除坏分支.但不幸的是,它并不是一直有效.MSVC是一个很好的编译器,并且成功地消除了坏分支,但是GCC的结果是混合的,这取决于版本,测试类型,以及对64位比对32位的影响更大.
真奇怪.而且这也意味着无法确保编译器处理运行时测试.
编辑3:这些天,我正在使用编译时常量联合,期望编译器将其解析为明确的是/否信号.它运作得很好:https: //godbolt.org/g/DAafKo
用于查询程序运行的硬件或操作系统功能属性的标准C++功能和实用程序是什么?
例如,std::thread::hardware_concurrency()
为您提供机器支持的线程数.
但是,如何检测计算机具有多少RAM,或者进程使用了多少RAM,或者在某个目录中可以写入多少磁盘空间,或者有多少L2缓存可用?
我有一个非常简单的问题,这对我来说很难,因为这是我第一次尝试使用二进制文件,我不太了解它们.我想要做的就是将一个整数写入二进制文件.
我是这样做的:
#include <fstream>
using namespace std;
int main () {
int num=162;
ofstream file ("file.bin", ios::binary);
file.write ((char *)&num, sizeof(num));
file.close ();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我做错了什么,你能告诉我什么?
给我带来麻烦的部分是与file.write一致,我不明白.
先感谢您.