Один и тот же код C, сгенерированный f2c, построенный с помощью gcc на 2 платформах, дает разные результаты

У нас есть странная проблема с нашим кодом, мы использовали один и тот же код в течение нескольких лет на нескольких платформах, но в этом году нам нужно было собрать наше программное обеспечение на 64-битной системе RHEL 8.

Во время обработки сборки нам нужно преобразовать код F77 в код C с помощью инструментов f2c.

Во время этой обработки преобразования некоторые переменные в памяти определяются таким образом в выходном файле 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) мы получаем хорошие результаты, когда строим код C с помощью GCC.

В Opensuse: прочитанное значение находится по адресу + 5 x краткий размер шрифта (2) ==>(10)

Но в RHEL тот же код C возвращает неверное значение адреса:

На RHEL 8: чтение v_cncal значение находится по адресу + 5 x int type size (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)

...

2 ответа

Это неопределенное поведение, поскольку оно нарушает правила строгого псевдонима. когда вы разыменовываете (Я считаю, что это )

И в результате получается один из наиболее распространенных способов «работы» UB - получение разных результатов с использованием разных компиляторов при запуске на разных платформах.

Как было сказано в ответе , вы запускаете UB из-за нарушения строгих правил алиасинга.

Однако я предполагаю, что проблема может быть вызвана неправильным выравниванием. Выражение (&dovit_1 + 5))выглядит очень подозрительно, потому что это неправильно выровненный указатель на 4-байтовое int. Некоторые платформы позволяют читать только правильно выровненные указатели, и компиляторы используют это преимущество, «настраивая» указатели.

Кстати. v_cncal__читает значение по адресу + 5 x short int type size (2)", а не просто" int (size 4)". Тип dovit_1 является short int насколько я понимаю.

Я предполагаю, что арифметика указателя должна выполняться после приведения. Заменять

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

с участием

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

Это помогло?

Другие вопросы по тегам