技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 413|回复: 10
收起左侧

【C】且看自己实现的字节顺序转换语句无法被MSVC和GCC优化

[复制链接]

995

主题

2202

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16298 个
贡献
31909 次
宅之契约
0 份
在线时间
1556 小时
注册时间
2014-1-26
发表于 2018-6-12 12:56:05 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
[C] 纯文本查看 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<string.h>

int main()
{
	uint32_t a;
	scanf("%x", &a);

	printf("%x\n", ((a & 0x0ff) << 24) | ((a & 0x0ff00) << 8) | ((a & 0xff0000) >> 8) | ((a & 0xff000000) >> 24));
	return 0;
}
这份代码,用scanf从stdin读取一个十六进制数值,存入变量a,然后用printf打印,把a的字节顺序大小端转换了一下。

我预想VS大概会使用类似bswapd之类的指令来实现的吧,然而,否。

bswapd.png

编译设置是Win32 Release,优化参数是/O2。试过/Ox效果一样。

然后看看gcc的效果。
版本:gcc version 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC)
编译命令:gcc -m32 -O3 a.c -o a.o

gcc.png

我预想GCC大概就会使用类似bswapd之类的指令来实现的吧,然而,否。

继续测试。此时我要使用htonl、ntohl等类似函数,看会怎样。

[C] 纯文本查看 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<string.h>
#include<winsock2.h>

int main()
{
	uint32_t a;
	scanf("%x", &a);

	printf("%x\n", htonl(a));
	return 0;
}
htonl.png

asm.png

划重点:
00841012  push        dword ptr [esp]  
00841015  call        dword ptr ds:[84B108h]  

call [84B108h]是什么鬼,跟过去看看:
mem.png
一个函数指针来着。地址是0x75692d57。这应该是htonl这个API的地址了。
那么htonl是怎么实现的呢?
看!
api.png
API竟然也是用一系列啰嗦的位移等各种运算实现的字节顺序改变,而且和我自己写的那个非常像。
难道说,这种方法比用单一的一条bswapd指令更好?我们来看看GCC是怎么做的。

还是那份代码(<winsock2.h>换成<sys/socket.h>),还是那个编译命令(gcc -m32 -O3 a.c -o a.o),让我们看看效果。
gcc_.png
gcc也是调用函数的方式调用的htonl,这是可以理解的。因为htonl并不是单纯地进行字节顺序的改变。它会根据当前系统是BE还是LE来判断要不要改变字节顺序。所以这是个API,是一个系统相关的玩意儿。不能误解它。

此处有资料:
https://stackoverflow.com/questions/
21527957
/htonl-vs-builtin-bswap32


根据glibc的源码,_htonl在需要进行字节顺序转换的时候,是用__builtin_bswap32实现的。所以我们要看__builtin_bswap32这个GCC钦定函数是怎么实现的。
[C] 纯文本查看 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<inttypes.h>
#include<string.h>
#include<sys/socket.h>

int main()
{
	uint32_t a;
	scanf("%x", &a);

	printf("%x\n", __builtin_bswap32(a));
	return 0;
}
builtin.png
GCC的__builtin_bswap32在x86平台上确实就是用bswap(严格来说32位版本的bswap写作bswapd)指令实现的,而且是内联的。

补充:
根据4楼的补充,386没有bswap,而Win7的
x
86版本是兼容386的。所以要自己运算实现。
但我仍然觉得这是Win7优化不足,因为如果是我来实现的话,指令会更简短,并且对内存的读写会减少。详见5楼。

结论:
1、MSVC和GCC都不能把以下的宏优化为你所想的单条指令实现字节顺序变换。

    #define byteswapd(a) ((((a) & 0x0ff) << 24) | (((a) & 0x0ff00) << 8) | (((a) & 0xff0000) >> 8) | (((a) & 0xff000000) >> 24))

2、Windows平台上的htonl作为API,竟然也是这么蠢,没有使用bswapd,更像是上述宏的展开。(Windows 7 旗舰版 x64+VS2012)
3、GCC有__builtin_bswap32这个内置钦定函数可以用于32位的字节顺序转换,用了bswapd,并且x86平台Linux上的htonl这个API也是用的这个指令。

参考资料:
htonl() vs __builtin_bswap32()
https://stackoverflow.com/questions/
21527957
/htonl-vs-builtin-bswap32

Other Built-in Functions Provided by GCC
https://gcc.gnu.org/
on
linedocs/gcc/Other-Builtins.html

23

主题

63

帖子

1408

积分

用户组: 管理员

UID
1043
精华
7
威望
29 点
宅币
1225 个
贡献
27 次
宅之契约
0 份
在线时间
246 小时
注册时间
2015-8-15
发表于 2018-6-12 13:13:52 | 显示全部楼层
我记得微软的编译器有_byteswap_ulong这个内置宏,还有_byteswap_uint64,_byteswap_ushort的对应64位,16位版本。你试试看?
flowers for Broken spirits - a woman turned into stake will hold the world in the basin of fire.

995

主题

2202

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16298 个
贡献
31909 次
宅之契约
0 份
在线时间
1556 小时
注册时间
2014-1-26
 楼主| 发表于 2018-6-12 15:20:23 | 显示全部楼层
tangptr@126.com 发表于 2018-6-12 13:13
我记得微软的编译器有_byteswap_ulong这个内置宏,还有_byteswap_uint64,_byteswap_ushort的对应64位,16位 ...

但!htonl这API竟然没有使用这个玩意儿来优化。

25

主题

81

帖子

1088

积分

用户组: 版主

UID
1821
精华
6
威望
57 点
宅币
832 个
贡献
31 次
宅之契约
0 份
在线时间
196 小时
注册时间
2016-7-12
发表于 2018-6-12 19:13:32 | 显示全部楼层
bswap指令386的处理器不支持。

995

主题

2202

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16298 个
贡献
31909 次
宅之契约
0 份
在线时间
1556 小时
注册时间
2014-1-26
 楼主| 发表于 2018-6-13 16:15:43 | 显示全部楼层
Ayala 发表于 2018-6-12 19:13
bswap指令386的处理器不支持。


查看了一下……尴尬,还真是这样。
但如果是我,我会这样用汇编来实现:
mov eax,要转换的数(比如[esp+4])
mov dx,ax
shr eax,16
xchg dl,dh
xchg al,ah
shl edx,16
or eax,edx
ret

0

主题

8

帖子

49

积分

用户组: 初·技术宅

UID
2928
精华
0
威望
1 点
宅币
39 个
贡献
0 次
宅之契约
0 份
在线时间
6 小时
注册时间
2017-10-7
发表于 2018-6-13 16:40:25 | 显示全部楼层
这多艹蛋蛋  每次都转  感觉怪怪的   传过来的图都是反色的  蛋蛋疼

995

主题

2202

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16298 个
贡献
31909 次
宅之契约
0 份
在线时间
1556 小时
注册时间
2014-1-26
 楼主| 发表于 2018-6-13 16:42:19 | 显示全部楼层
sml2 发表于 2018-6-13 16:40
这多艹蛋蛋  每次都转  感觉怪怪的   传过来的图都是反色的  蛋蛋疼

和图有什么卵关系

0

主题

8

帖子

49

积分

用户组: 初·技术宅

UID
2928
精华
0
威望
1 点
宅币
39 个
贡献
0 次
宅之契约
0 份
在线时间
6 小时
注册时间
2017-10-7
发表于 2018-6-13 16:46:02 | 显示全部楼层
0xAA55 发表于 2018-6-13 16:42
和图有什么卵关系

自己写的Linux截图进程 截完后再传到Win上  图全是反色的 RBG 变成了 GBR

995

主题

2202

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16298 个
贡献
31909 次
宅之契约
0 份
在线时间
1556 小时
注册时间
2014-1-26
 楼主| 发表于 2018-6-13 18:31:18 | 显示全部楼层
sml2 发表于 2018-6-13 16:46
自己写的Linux截图进程 截完后再传到Win上  图全是反色的 RBG 变成了 GBR

RGB和BGR与字节顺序无关,是图像颜色格式的概念了。

0

主题

8

帖子

49

积分

用户组: 初·技术宅

UID
2928
精华
0
威望
1 点
宅币
39 个
贡献
0 次
宅之契约
0 份
在线时间
6 小时
注册时间
2017-10-7
发表于 2018-6-14 11:25:42 | 显示全部楼层
0xAA55 发表于 2018-6-13 18:31
RGB和BGR与字节顺序无关,是图像颜色格式的概念了。

我懂你意思 问题是Integer传过去也反了...

4

主题

20

帖子

50

积分

用户组: 小·技术宅

UID
4127
精华
0
威望
0 点
宅币
30 个
贡献
0 次
宅之契约
0 份
在线时间
1 小时
注册时间
2018-8-6
发表于 2018-8-6 09:12:28 | 显示全部楼层
谢谢分享
回复

使用道具 举报

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号|网站地图

GMT+8, 2018-8-18 23:57 , Processed in 0.107580 second(s), 17 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表