C++常见几种输出方法评测(int && long long)

本文评测了C++中三种常见的输出方法:cout、取消iostream缓存后的cout以及printf。在Intel Pentium G530处理器和DDR3 1333 2GB内存环境下,使用cena软件和NOI2011道路建设后五个测试点的数据进行评测。评测内容包括输入输出效率的比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.概览

说实话我就是喜欢cout,因为简单,不用记住%lld,%64d,%d,%s,%f,%lf之类的,所以从来不用printf。但是因为输入的巨大差距(见另一篇文章http://blog.youkuaiyun.com/cym19981017/article/details/49487549),所以我决定再写一篇关于输出的评测。
  1. cout
  2. cout(打消iostream的输入输出缓存)
  3. printf

二.环境介绍

评测软件:cena
评测数据:noi2011道路建设后五个测试点,将输入的再输出一次;
这里写图片描述
评测环境:
处理器:Intel pentium G530 2.4GHZ 双核
内存:DDR3 1333 2GB 双通道
输入方式:
为了公平起见,和对系统的依赖尽可能少,全部scanf读入。

三.评测方式介绍

1.cout

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#include<vector>
#include<climits>
#include<string>
#include<cstdlib>
#include<set>
#include<stack>
#include<ctime>
<think>我们有一个整数 input_int,需要将其截断为32位无符号长整型(unsigned long),并确保只保留低32位,高位被屏蔽掉。 在C/C++中,unsigned long类型的大小取决于平台(可能是32位或64位)。但是,用户明确要求32位,所以我们需要确保无论平台是32位还是64位,都只保留低32位。 方法: 1. 我们可以使用位操作,将input_int与0xFFFFFFFF(即32位全1)进行按位与(&)操作,这样无论input_int是多少位,结果都只保留低32位,高位归零。 2. 但是,需要注意的是,在C++中,0xFFFFFFFF是一个无符号整数字面量,它的类型可能是unsigned int或unsigned long,具体取决于平台。在32位平台上,unsigned int通常是32位,而0xFFFFFFFF可能正好是unsigned int;在64位平台上,0xFFFFFFFF可能会被当作32位,但当我们赋值给unsigned long(64位)时,它会被提升为64位(即0x00000000FFFFFFFF),这样按位与操作后,高32位会被清零,低32位保留。 然而,为了确保代码的明确性和可移植性,我们可以显式地使用一个32位的掩码,并确保我们得到的是32位的结果。 但是,注意:unsigned long在有些平台上是32位,有些是64位。如果我们要求结果一定是32位,那么我们可以使用固定宽度的整数类型,如uint32_t(在cstdint头文件中),这样就能确保是32位无符号整数。 如果用户坚持使用unsigned long,并且要求是32位,那么我们需要确保在64位平台上,我们只保留低32位。 因此,我们可以这样做: unsigned long result = input_int & 0xFFFFFFFFUL; 但是,0xFFFFFFFFUL在32位平台上是一个32位的无符号长整数,在64位平台上,0xFFFFFFFFUL表示的是0x00000000FFFFFFFF(因为UL在64位平台上是64位,而0xFFFFFFFF不足64位,所以高位补0)。这样按位与操作后,在64位平台上,result的高32位是0,低32位是input_int的低32位;在32位平台上,由于unsigned long是32位,所以0xFFFFFFFFUL就是32位全1,按位与后得到低32位。 然而,这里有一个问题:当input_int是负数时(有符号整数),我们将其转换为无符号长整数,然后再进行按位与。按位与操作对于无符号整数是直接操作二进制位。所以,如果input_int是负数,它的二进制表示是补码形式,我们取低32位,然后将其视为无符号整数。 但是,用户要求的是“无符号长整型”,所以负数的情况也会被自动转换为无符号整数(即按照模运算转换)。 另一种方法是使用强制类型转换和位掩码: unsigned long result = (input_int & 0xFFFFFFFFUL); 但是,在64位平台上,0xFFFFFFFFUL是64位整数(值为0x00000000FFFFFFFF),所以input_int & 0xFFFFFFFFUL 会得到一个64位的整数,但低32位是input_int的低32位,高32位为0。这正好符合要求。 然而,在32位平台上,0xFFFFFFFFUL是32位全1,所以按位与后还是32位。 但是,如果input_int是64位整数(比如long long),那么在32位平台上,input_int可能超过32位,但按位与0xFFFFFFFFUL(32位全1)时,会发生整型提升。input_int会被提升为unsigned long(32位)?注意:如果input_int是64位整数,而0xFFFFFFFFUL是32位,那么在进行按位与之前,0xFFFFFFFFUL会被提升为64位(即0x00000000FFFFFFFF),然后按位与操作后,得到低32位。 但是,在32位平台上,编译器通常不支持64位整数,除非使用long long。所以,为了确保安全,我们可以先将input_int转换为一个至少32位(或更多位)的无符号整数,然后取低32位。 更通用的方法是使用uint32_t类型,然后赋值给unsigned long。但是,如果用户要求使用unsigned long,我们可以: unsigned long result = (unsigned long)(input_int & 0xFFFFFFFFUL); 但是,这样写可能还是不够清晰,因为0xFFFFFFFFUL在32位和64位平台上的大小不同。 实际上,我们想要的是低32位,所以我们可以使用: unsigned long result = (unsigned long)(input_int & 0xFFFFFFFF); 这里,0xFFFFFFFF的类型可能是unsigned int(在32位和64位平台上,unsigned int通常是32位)。然后,我们将其转换为unsigned long。这样,在32位平台上,unsigned long是32位,所以转换后不变;在64位平台上,unsigned long是64位,转换后,由于0xFFFFFFFF是32位,所以结果是一个32位的值(高32位为0)赋给64位变量,所以高32位为0,低32位为input_int的低32位。 但是,如果input_int是64位整数(比如long long),那么input_int & 0xFFFFFFFF 的结果是一个32位的整数(因为0xFFFFFFFF是32位,所以按位与后的结果类型可能是unsigned int,32位),然后转换为unsigned long(64位)时,会进行零扩展(因为原值是无符号的),所以结果仍然是低32位。 但是,如果input_int是负数(有符号整数),那么在进行input_int & 0xFFFFFFFF时,0xFFFFFFFF是无符号整数(32位),根据C/C++的整型提升规则,input_int会被转换为无符号整数(即先取模,再按位与)。所以,这样操作也能得到正确的低32位。 因此,我们可以这样写: unsigned long result = (unsigned long)(input_int & 0xFFFFFFFFU); 注意:这里使用U后缀表示无符号整数,确保0xFFFFFFFFU是unsigned int类型(32位)。 但是,这里有一个潜在问题:当int是16位时,0xFFFFFFFFU会超出unsigned int的范围?实际上,在标准中,int至少16位,而0xFFFFFFFFU对于16位int来说,是一个大于16位的数,所以它会被视为unsigned long(在16位平台上,unsigned int是16位,0xFFFFFFFFU会超出unsigned int,所以编译器会将其视为unsigned long,但这样的平台现在很少见)。所以,为了更好的可移植性,我们可以使用: unsigned long result = (unsigned long)(input_int & 0xFFFFFFFFUL); 这样,在16位平台上,0xFFFFFFFFUL会被视为unsigned long(32位),然后按位与操作会将input_int提升为unsigned long,然后取低32位(如果input_int是16位,则高16位为0,然后按位与后还是原来的值,因为0xFFFFFFFFUL的低16位是全1,但高16位也是全1?不对,0xFFFFFFFFUL在32位平台上就是32位全1,在16位平台上,unsigned long是32位,所以0xFFFFFFFFUL就是32位全1。所以按位与后,input_int被提升为32位(符号扩展?不,有符号整数提升为无符号整数时,会先转换为等价的模值,然后再按位与)?这有点复杂。 实际上,我们只需要确保取低32位,所以无论input_int是什么类型,我们都可以先将其转换为uint32_t(如果支持的话),然后再赋值给unsigned long。 但是,如果用户的环境不支持C99或C++11,可能没有uint32_t。所以,我们可以使用条件编译,或者使用上述掩码方法。 考虑到现在大多数平台都是32位或64位,我们可以采用: unsigned long result = (input_int & 0xFFFFFFFFUL); 但是,在16位平台上,unsigned long可能是32位,这样写也是正确的。 然而,用户要求的是32位,所以即使是在16位平台上,我们也要得到32位的结果(但16位平台可能没有32位寄存器,但unsigned long可以是32位)。所以,这样写是可行的。 另一种更简单的方法:直接使用模运算(模2^32),因为截断低32位相当于模2^32。 unsigned long result = (unsigned long)(input_int % (1ULL<<32)); 但是,模运算对于负数可能不直接等价于按位与(因为C/C++中,负数的模运算结果取决于具体实现,但通常对于无符号模数,会先转换为无符号整数)。所以,我们不推荐使用模运算。 因此,最可靠的方法还是按位与。 总结:使用按位与0xFFFFFFFFUL,然后赋值给unsigned long。 但是,如果input_int是64位整数,而0xFFFFFFFFUL在64位平台上是64位(值为0xFFFFFFFF,即0x00000000FFFFFFFF),那么按位与后,得到的是input_int的低32位,高32位被清零。然后赋值给unsigned long(64位)没有问题。 在32位平台上,0xFFFFFFFFUL是32位全1,按位与后得到input_int的低32位(如果input_int是32位以上,则会被截断,因为32位平台上的int通常只有32位,但long long是64位,这时按位与操作会先将input_int转换为unsigned long(32位)?这样就会丢失高32位?所以,如果input_int是64位整数,在32位平台上,表达式input_int & 0xFFFFFFFFUL 会先将0xFFFFFFFFUL转换为64位(因为input_int是64位),然后按位与,得到低32位,然后赋值给unsigned long(32位)时,会再次截断(只取低32位,但这时已经只有低32位了,所以没问题)。 但是,在32位平台上,unsigned long是32位,所以64位整数赋值给32位整数会丢失高32位,但这里我们已经用掩码将高32位清零了,所以低32位就是我们要的。 所以,我们可以这样写: unsigned long result = (input_int & 0xFFFFFFFFUL); 但是,如果input_int是64位整数(比如long long),在32位平台上,0xFFFFFFFFUL是32位(无符号长整型),那么表达式input_int & 0xFFFFFFFFUL 会先将0xFFFFFFFFUL提升为64位(因为input_int是64位),提升后为0x00000000FFFFFFFF(64位),然后按位与,得到input_int的低32位(高32位被清零),然后赋值给32位的unsigned long时,会截取这个64位数的低32位(因为unsigned long是32位),而低32位就是我们需要的,所以没有问题。 因此,无论input_int是什么整型(char, short, int, long, long long),无论平台是32位还是64位,上述表达式都能正确取到低32位,并存储在unsigned long中(在32位平台上,unsigned long是32位,正好存储;在64位平台上,unsigned long是64位,存储的值是0到2^32-1之间的数,高32位为0)。 但是,有一个例外:如果input_int是比unsigned long还大的类型(比如在64位平台上,input_int是128位整数),那么按位与操作后,结果是一个128位整数,然后赋值给unsigned long(64位)时,会进行截断(取低64位),而我们的按位与操作已经将高96位清零,所以低32位被保留,然后赋值时取低64位(其中低32位是我们要的,高32位是0),所以结果也是正确的。 因此,我们可以使用: unsigned long result = input_int & 0xFFFFFFFFUL; 但是,为了确保类型正确,避免符号扩展等问题,我们可以先将input_int转换为无符号整数类型,然后再进行按位与。不过,按位与操作本身会处理符号问题(因为无符号整数的位操作是确定的)。 所以,最终代码: unsigned long result = input_int & 0xFFFFFFFFUL; 但是,我们也可以写成: unsigned long result = (input_int & 0xFFFFFFFFUL); 注意:如果input_int是浮点数,那么上述操作是不允许的。但题目要求是整数,所以假设input_int是整型。 另外,如果input_int是有符号整数且为负,那么按位与操作后,我们得到的是其低32位的无符号表示。例如,input_int = -1,则-1的补码表示是所有位都是1(假设用足够多的位表示),那么与0xFFFFFFFFUL按位与后,就得到0xFFFFFFFF(32位全1),即2^32-1,这是一个无符号数。这符合用户要求:截断为32位无符号长整型。 因此,这个表达式可以正确处理正负数。 结论:使用 `unsigned long result = input_int & 0xFFFFFFFFUL;` 即可。 但是,我们也可以考虑使用C++的固定宽度整数类型(如果可用的话),这样更清晰: #include <cstdint> uint32_t result = static_cast<uint32_t>(input_int & 0xFFFFFFFFU); 然后,如果需要unsigned long,可以再转换: unsigned long result = static_cast<unsigned long>(static_cast<uint32_t>(input_int & 0xFFFFFFFFU)); 但这样写有点繁琐,而且用户要求使用unsigned long。所以,如果用户的环境支持C++11,我们可以用uint32_t,否则用前面那种方法。 但是,用户没有说明环境,所以我们用通用的方法。 因此,我们推荐: unsigned long result = input_int & 0xFFFFFFFFUL; 但是,在C++中,字面量UL表示unsigned long,而0xFFFFFFFFUL在32位平台上就是32位全1,在64位平台上也是32位全1(因为0xFFFFFFFFUL的值是4294967295,即2^32-1),所以按位与操作后,总是得到低32位。 所以,这个方法是可行的。 注意:在C++中,如果input_int是比unsigned long更大的类型(如long long),那么按位与操作会先将0xFFFFFFFFUL转换为input_int的类型(整型提升),然后再按位与。所以,只要input_int是整数类型,这个表达式就是正确的。 因此,我们这样写即可。 示例代码: #include <iostream> using namespace std; int main() { long long input_int = 0x1234567890ABCDEFLL; // 64位整数 unsigned long result = input_int & 0xFFFFFFFFUL; // 在64位平台上,result应该等于0x90ABCDEF(低32位) // 在32位平台上,result也是0x90ABCDEF(低32位) cout << hex << result << endl; } 在64位平台运行,输出:90abcdef 在32位平台运行,同样输出:90abcdef 但是,在32位平台上,long long是64位,而0xFFFFFFFFUL是32位,所以表达式input_int & 0xFFFFFFFFUL会先将0xFFFFFFFFUL提升为64位(值为0x00000000FFFFFFFF),然后按位与,得到0x0000000090ABCDEF,然后赋值给unsigned long(32位)时,会截取低32位(0x90ABCDEF)。所以输出90abcdef。 所以,这个方法是正确的。 但是,如果input_int是0x1234567890ABCDEF,在64位平台上,result被赋值为0x90ABCDEF,然后以十六进制输出输出的是90abcdef,这是正确的。 因此,我们使用这个表达式即可。 最后,注意:如果input_int是浮点数,则代码会编译失败。所以,确保input_int是整数类型。 回答总结:使用按位与操作,掩码为0xFFFFFFFFUL,即可将任意整数的低32位保留,并赋值给unsigned long类型。</think>在C/C++中,将任意整数 `input_int` 截断为32位无符号长整型(`unsigned long`),并屏蔽高位(只保留低32位)可通过以下方法实现: ### 核心方法:位掩码操作 ```cpp unsigned long result = input_int & 0xFFFFFFFFUL; ``` - **原理**: - `0xFFFFFFFFUL` 是一个无符号长整型字面量,其二进制表示为 **32个1**(即 `1111 1111 1111 1111 1111 1111 1111 1111`)。 - 按位与操作 `&` 会将 `input_int` 的高位全部置零,仅保留低32位的值。 - 无论 `input_int` 是正数、负数,还是超过32位的整数(如 `long long`),此操作均能正确截断。 ### 关键说明 1. **符号处理**: - 若 `input_int` 为负数,其补码表示的低32位会被保留,结果转换为无符号值(例如 `-1` 会变为 `0xFFFFFFFF`)。 - 示例: ```cpp int input_int = -1; // 补码: 0xFFFFFFFF (32位) unsigned long result = input_int & 0xFFFFFFFFUL; // result = 4294967295 (0xFFFFFFFF) ``` 2. **跨平台兼容性**: - `unsigned long` 在32位系统为32位,在64位系统通常为64位,但掩码操作确保结果始终是32位值。 - 在64位系统中,高位被显式清零: ```cpp long long input_int = 0x123456789ABC; // 64位整数 unsigned long result = input_int & 0xFFFFFFFFUL; // 低32位: 0xFFFF9ABC ``` 3. **类型安全**: - 使用 `UL` 后缀确保掩码为无符号长整型,避免符号扩展问题。 - 若需明确32位类型,可用 `<cstdint>` 中的 `uint32_t`: ```cpp #include <cstdint> uint32_t result = input_int & 0xFFFFFFFFU; // 显式32位类型 ``` ### 完整示例代码 ```cpp #include <iostream> #include <cstdint> // 可选,用于uint32_t int main() { long long input_int = 0x1234567890ABCDEF; // 64位测试值 unsigned long truncated = input_int & 0xFFFFFFFFUL; std::cout << "原始值: 0x" << std::hex << input_int << std::endl; std::cout << "截断值: 0x" << truncated << std::endl; // 输出 0x90ABCDEF return 0; } ``` ### 注意事项 - **整数提升规则**:若 `input_int` 类型小于 `int`(如 `char`),会先提升为 `int` 再操作,不影响结果。 - **浮点数处理**:此方法仅适用于整数类型。若输入为浮点数,需先显式转换为整数: ```cpp double input_float = 123.456; unsigned long result = static_cast<long>(input_float) & 0xFFFFFFFFUL; ``` 此方法符合C++类型安全原则,避免了强制转型的风险,并确保在所有常见平台上行为一致[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值