0

我们的代码有一个奇怪的问题,多年来我们在多个平台上使用相同的代码,但今年我们需要在 64 位 RHEL 8 系统上构建我们的软件。

在构建过程中,我们需要使用 f2c 工具将一些 F77 代码转换为 C 代码。

在此转换处理期间,内存中的一些变量在输出 C 文件中像这样定义。

#define v_hhdcb__ ((shortint *)&dovit_1 + 1608) /* works perfectly */
#define v_cncal__ ((integer *)(&dovit_1 + 5)) /* dovit_1 is a an array of short /*

在我们所有的系统(HP-UX、AIX、Ubuntu、openSUSE)上,当我们使用 GCC 构建 C 代码时,我们获得了良好的价值。

在 Opensuse 上:读取v_cncal值在dovit_1地址 + 5 x 短类型大小 (2) == > (10)

但在 RHEL 上,相同的 C 代码返回错误的地址值:

在 RHEL 8 上:读取v_cncal值位于dovit_1地址 + 5 x int 类型大小 (4) ==> (20) 但dovit_1它是一个short数组而不是int数组。

GCC 版本在这两种情况下 8.4 和相同的 f2c 编译器

有什么问题?

更新

在调试过程中,我们尝试像这样手动修改 C 代码:

#define v_cncal__ ((integer *)(&dovit_1 + 5*sizeof(shortint))) /* works */

但是这个 C 代码是由 f2c 生成的,我认为最好的方法是让 f2c 开发团队知道发生了什么。

更新 1

dovit_1 如何声明:

/* testdyF.f -- translated by f2c (version 20181026).
   You must link the resulting object file with libf2c:
        on Microsoft Windows system, link with libf2c.lib;
        on Linux or Unix systems, link with .../path/to/libf2c.a -lm
        or, if you install libf2c.a in a standard place, with -lf2c -lm
        -- in that order, at the end of the command line, as in
                cc *.o -lf2c -lm
        Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,

                http://www.netlib.org/f2c/libf2c.zip
*/

union {
    struct {
        shortint dovita[1];

    } _1;
    struct {
        doublereal eqv_pad[1];

    } _2;
} dovit_;

#define dovit_1 (dovit_._1)
#define dovit_2 (dovit_._2)

/* Table of constant values */

static integer c__9 = 9;
static integer c__1 = 1;
static integer c__2 = 2;
static integer c__3 = 3;

shortint        *__dovit;
#undef dovit_1
#define dovit_1 __dovit[0]

/* CCCC Tag pour ajout routine d attachement shm */
#include <SHM_INIT.c>

/* _SHM_INIT */
/* Main program */ int MAIN__(void)
{
    /* Builtin functions */
    integer s_wsle(cilist *), do_lio(integer *, integer *, char *, ftnlen),
            e_wsle(void);

    /* Local variables */
#define v_pc__ ((shortint *)&dovit_1 + 288100)
#define v_cp__ ((shortint *)&dovit_1 + 288169)
#define v_ct__ ((shortint *)&dovit_1 + 294500)

...
4

2 回答 2

0

正如在回答中所说,由于违反了严格的别名规则,您触发了 UB。

但是,我猜你的问题可能是由无效对齐引起的。表达式(&dovit_1 + 5))看起来很可疑,因为它没有正确对齐指向 4 字节长 int 的指针。一些平台只允许读取正确对齐的指针,编译器通过“调整”指针来利用这一点。

顺便提一句。 在地址 + 5 x short intv_cncal__ type size (2)"处读取一个值,而不仅仅是“int (size 4)”。据我了解,类型是。dovit_1dovit_1short int

我想指针算术应该在演员表之后完成。代替

#define v_cncal__ ((integer *)(&dovit_1 + 5)) 

#define v_cncal__ ((integer *)&dovit_1 + 5)

有帮助吗?

于 2021-09-17T10:16:53.590 回答
0

这是未定义的行为,因为它违反了严格的别名规则。当你取消引用时integer *(我相信它是int *

结果是UB“工作”的最常见方式之一-在不同平台上运行时使用不同的编译器获得不同的结果。

于 2021-09-17T10:06:40.930 回答