如何在无gfortran警告的情况下用255等数值初始化Fortran字符数组
问题背景
我有一段用于处理气象格式GRIB2字节打包的Fortran代码,编写测试代码时需要初始化一个字符数组,代码如下:
! Storage for the grib2 message we are constructing. integer, parameter :: lcgrib = 191 character, dimension(lcgrib) :: cgrib ! This is the GRIB2 message we expect to get. character(kind = int8) :: expected_cgrib(lcgrib) = (/ achar( 71), achar( 82),& & achar( 73), achar( 66), achar( 0), achar( 0), achar( 0),& & achar( 2), achar( 0), achar( 0), achar( 0), achar( 0),& & achar( 0), achar( 0), achar( 0), achar(191), achar( 0),& & achar( 0), achar( 0), achar( 21), achar( 1), achar( 0),& & achar( 7), achar( 0), achar( 4), achar( 2), achar( 24),& & achar( 0), achar( 7), achar(229), achar( 11), achar( 13),& & achar( 15), achar( 59), achar( 59), achar( 1), achar( 0),& & achar( 0), achar( 0), achar( 0), achar( 8), achar( 2),& & achar( 1), achar( 2), achar( 3), achar( 0), achar( 0),& & achar( 0), achar( 72), achar( 3), achar( 0), achar( 0),& & achar( 0), achar( 0), achar( 4), achar( 0), achar( 0),& & achar( 0), achar( 0), achar( 0), achar( 1), achar( 0),& & achar( 0), achar( 0), achar( 1), achar( 1), achar( 0),& & achar( 0), achar( 0), achar( 1), achar( 1), achar( 0),& & achar( 0), achar( 0), achar( 1), achar( 0), achar( 0),& & achar( 0), achar( 2), achar( 0), achar( 0), achar( 0),& & achar( 2), achar( 0), achar( 0), achar( 0), achar( 0),& & achar( 0), achar( 0), achar( 0), achar( 0), achar( 0),& & achar( 0), achar( 0), achar( 45), achar( 0), achar( 0),& & achar( 0), achar( 91), achar( 0), achar( 0), achar( 0),& & achar( 0), achar( 55), achar( 0), achar( 0), achar( 0),& & achar(101), achar( 0), achar( 0), achar( 0), achar( 5),& & achar( 0), achar( 0), achar( 0), achar( 5), achar( 0),& & achar( 0), achar( 0), achar( 0), achar( 34), achar( 4),& & achar( 0), achar( 0), achar( 0), achar( 0), achar( 0),& & achar( 0), achar( 0), achar( 0), achar( 0), achar( 0),& & achar( 12), achar( 59), achar( 0), achar( 0), achar( 0),& & achar( 0), achar( 0), achar( 1), achar( 1), achar( 0),& & achar( 0), achar( 0), achar( 1), achar( 2), achar( 1),& & achar( 0), achar( 0), achar( 0), achar( 1), achar( 0),& & achar( 0), achar( 0), achar( 21), achar( 5), achar( 0),& & achar( 0), achar( 0), achar( 4), achar( 0), achar( 0),& & achar( 65), achar( 48), achar( 0), achar( 0), achar( 0),& & achar( 1), achar( 0), achar( 1), achar( 8), achar( 0),& & achar( 0), achar( 0), achar( 0), achar( 6), achar( 6),& & achar(255), achar( 0), achar( 0), achar( 0), achar( 9),& & achar( 7), achar( 0), achar( 1), achar( 1), achar( 2),& & achar( 55), achar( 55), achar( 55), achar( 55) /)
报错信息
使用GNU gfortran编译时抛出如下错误:
84 | & achar(255), achar( 0), achar( 0), achar( 0), achar( 9),& | 1 Error: Argument of ACHAR function at (1) outside of range [0,127] [-Werror=surprising]
问题描述
报错原因是初始化字符数组的部分整型值超过127,不属于ASCII定义范围。有没有不需要显式关闭告警就能避免该问题的方法?Fortran中是否支持用单字节无符号整数值序列初始化字符数组?
解决方法
achar()默认对应ASCII字符集,参数合法范围就是0-127,超出范围触发告警属于正常的静态检查逻辑。可以用以下两种标准Fortran语法解决,不需要关闭任何编译告警:
- 方法一:使用
transfer()函数直接做类型转换transfer()是Fortran标准内置的内存拷贝转换函数,不会做字符集范围校验,直接把二进制内容按目标类型解析,完全适配0-255的单字节取值场景。
首先在代码开头引入标准内置模块获取int8类型定义:
use, intrinsic :: iso_fortran_env, only: int8
然后把原来的初始化逻辑替换为:
character(kind=int8) :: expected_cgrib(lcgrib) = transfer([ & 71_int8, 82_int8, 73_int8, 66_int8, 0_int8, 0_int8, 0_int8, & 2_int8, 0_int8, 0_int8, 0_int8, 0_int8, 0_int8, 0_int8, 0_int8, & 191_int8, 0_int8, 0_int8, 0_int8, 21_int8, 1_int8, 0_int8, & ! 剩余数值按原顺序补充,所有数值都加_int8后缀指定为单字节整数 & 55_int8, 55_int8, 55_int8, 55_int8], expected_cgrib)
这种方法是跨编译器兼容的标准写法,不会产生任何告警,也不会出现字节序问题,非常适合二进制格式的初始化场景。
- 方法二:给
achar()指定kind参数
如果不想修改大量初始化代码,可以直接给achar()增加kind入参,明确指定生成单字节字符,gfortran就不会再做ASCII范围校验:
把原来的achar(255)修改为achar(255, kind=int8)即可,所有超出127的数值都按此规则修改。
内容的提问来源于stack exchange,提问作者Edward Hartnett
相关产品推荐
相关产品推荐

