Три разных определения функции, ошибки компоновщика; как это может быть?

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

inst_dp_vec2.cc:

void loadSOAFVec(InstVector &ivector,
                 const FVec &ret,
                 const Address *a,
                 int soanum,
                 int soalen,
                 string mask) {
    if (soalen == 2) {
        ivector.push_back(new LoadFVec(ret, a, string("")));
    } else {
        printf("SOALEN = %d not supported at %s:%d\n", soalen, __FILE__,
               __LINE__);
        exit(1);
    }
}

inst_dp_vec4.cc

void loadSOAFVec(InstVector &ivector,
                 const FVec &ret,
                 const Address *a,
                 int soanum,
                 int soalen,
                 string mask) {
    if (soalen == 4) {
        ivector.push_back(new LoadFVec(ret, a, string("")));
    } else if (soalen == 2) {
        ivector.push_back(new LoadHalfFVec(ret, a, soanum));
    } else {
        UNSUPPORTED_SOALEN(soalen);
    }
}

inst_dp_vec8.cc

void loadSOAFVec(InstVector &ivector,
                 const FVec &ret,
                 const Address *a,
                 int soanum,
                 int soalen,
                 string mask) {
    int mskbits = (((1 << soalen) - 1) << (soanum * soalen));
    stringstream mk;
    mk << "0x" << hex << mskbits;
    string localmask = mk.str();
    ivector.push_back(new LoadUnpackFVec(ret, a, localmask));
}

команда компоновщика, выполняемая из файла Makefile (генерируется GNU Autotools) кажется, включает все три скомпилированных файла:

g++ -O3 -g -DNO_HW_MASKING -DUSE_LDUNPK -DUSE_PKST -DUSE_PACKED_GAUGES
-DUSE_PACKED_CLOVER -DNO_GPREF_L1 -DNO_GPREF_L2 -DENABLE_STREAMING_STORES
-DSERIAL_SPIN -DSOALEN=8 -DVECLEN=4 -DPRECISION=2 codegen.o data_types.o
dslash.o dslash_common.o inst_dp_vec8.o inst_sp_vec16.o inst_dp_vec4.o
inst_sp_vec8.o inst_sp_vec4.o inst_dp_vec2.o inst_scalar.o -o codegen

из моего знания одно правило определения, это должно дать линкер ошибка. Еще более странным является то, что версия от inst_dp_vec8.o не один используется, но один из inst_dp_vec4.cc, хотя он первым в командная строка компоновщика. Я изменил код так, что UNSUPPORTED_SOALEN бросает исключение и с GDB я нашел, что soalen = 8 активна. Из того, что я знаю о программном обеспечении, soalen = 8 работает только с veclen ≥ 8 такие, что только the inst_dp_vec8.cc может содержать правильное определение.

мой вопрос: как эта возможная ссылка на программу, которая может быть выполнена и не только из-за явного исключения с UNSUPPORTED_SOALEN?

1 ответов


потому что никакая диагностика не требуется, когда несколько определений происходят в нескольких единицах перевода.

из [basic.защита.odr]:

ни одна единица перевода не должна содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона.

и позже

каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется в этой программе вне отвергнутого утверждения (6.4.1); диагностика не требуется.

таким образом, вы получаете ошибку, если они являются несколькими определениями в исходном модуле, но не должны получать их, если они находятся в разных.