Конфликтные объявления в различных модулях перевода

Проблема

Анализ показывает ошибку или предупреждение похожего на одно из этих сообщений об ошибке:

  • Declaration of [...] is incompatible with a 
    declaration in another translation unit ([...])

    Это сообщение появляется, когда конфликтные объявления не прибывают из того же заголовочного файла.

  • Когда одно из конфликтных объявлений находится в заголовочном файле.

    Declaration of [...] had a different meaning during compilation of [...] ([...])

    Это сообщение появляется, когда конфликтные объявления прибывают из того же заголовочного файла, включенного в файлы другого источника.

Ошибка указывает, что та же переменная или функция или тип данных объявляются по-другому в различных модулях перевода. Конфликтные объявления нарушают Одно Правило Определения (cf. Стандарт C++, ISO/IEC 14882:2003, Раздел 3.2). Когда конфликтные объявления происходят, Polyspace® Code Prover™ не выбирает объявление и продолжает анализ.

Общие наборы инструментальных средств компиляции часто не хранят информацию типа данных во время процесса соединения. Конфликтные объявления не вызывают ошибки с вашим компилятором. Polyspace Code Prover следует более строгим стандартам для соединения, чтобы гарантировать отсутствие определенных ошибок времени выполнения.

Идентифицировать первопричину ошибки:

  1. Из сообщения об ошибке идентифицируйте эти два исходных файла с конфликтными объявлениями.

    Например, сообщение об ошибке выглядит так сообщение:

    C:\field.h, line 1: declaration of class "a_struct" had
          a  different meaning during compilation of "file1.cpp"
    | struct a_struct {
    |
    | Detected during compilation of secondary translation unit "file2.cpp"
    Сообщение показывает что структура a_struct имеет конфликтное объявление в file1.cpp и file2.cpp, оба из которых включают заголовочный файл field.h.

    Альтернативное сообщение об ошибке может выглядеть так:

    C:\field2.h, line 1: declaration of class "a_struct" had
          is incompatible with a declaration in another translation unit
    | the other declaration is at line 1 of field1.h"
    | struct a_struct {
    |
    | Detected during compilation of secondary translation unit "file2.cpp"
    Сообщение показывает что структура a_struct имеет конфликтное объявление в field2.h и field.h. Заголовочный файл field2.h включен в исходный файл file2.cpp.

  2. Попытайтесь идентифицировать конфликтные объявления в исходных файлах.

    В противном случае откройте модули перевода, содержащие эти файлы. Иногда, модули перевода или предварительно обработанные файлы показывают конфликтные объявления более ясно, чем исходные файлы потому что директивы препроцессору, такие как #include и #define операторы, заменяются соответственно, и макросы расширены.

    1. Повторно выполните анализ с флагом -keep-relaunch-files так, чтобы все модули перевода были сохранены. В пользовательском интерфейсе введите флаг для опции Other.

      Аналитические остановки после компиляции. Модули перевода или предварительно обработанные файлы хранятся в заархивированном файле ci.zip в подпапке .relaunch из папки результатов.

    2. Разархивируйте содержимое ci.zip.

      Предварительно обработанные файлы имеют то же имя как исходные файлы. Например, предварительно обработанный файл с file1.cpp назван file1.ci.

    Когда вы открываетесь, предварительно обработанные файлы в номерах строки утвердили в сообщении об ошибке, можно определить конфликтные объявления.

Возможная причина: объявление переменной и несоответствие определения

Объявление переменной не совпадает со своим определением. Например:

  • Объявление и определение используют различные типы данных.

  • Переменная объявлена столь же со знаком, но задана как без знака.

  • Объявление и определение используют спецификаторы другого типа.

  • Переменная объявлена как массив, но задана как непеременная типа массив.

  • Для переменной типа массив объявление и определение используют различные размеры массивов.

В этом примере код показывает соединяющуюся ошибку из-за несоответствия в спецификаторах типа. Объявление в file1.c не использует спецификаторы типа, но определение в file2.c использует volatile спецификатор.

file1.cfile2.c
extern int x;           

void main(void)
{/* Variable x used */}
 volatile int x;

В этих случаях можно обычно определять различие путем рассмотрения исходных файлов. Вы не должны видеть предварительно обработанные файлы.

Решение

Убедитесь, что объявление переменной совпадает со своим определением.

Возможная причина: объявление функции и несоответствие определения

Объявление функции не совпадает со своим определением. Например:

  • Объявление и определение используют различные типы данных в аргументах или возвращаемых значениях.

  • Объявление и определение используют различное количество аргументов.

  • Функция аргумента переменной или varargs объявляется в одной функции, но это называется в другой функции без предыдущего объявления.

    В этом случае сообщение об ошибке утверждает, что необходимый прототип для функции отсутствует.

В этом примере код показывает соединяющуюся ошибку из-за несоответствия в типе возврата. Объявление в file1.c имеет возвращаются, вводят int, но определение в file2.c имеет возвращаются, вводят float.

file1.cfile2.c
int input(void);

void main() {
  int val = input();
}
float input(void) {
  float x = 1.0;
  return x;
}

В этих случаях можно обычно находить различие путем рассмотрения исходных файлов. Вы не должны видеть предварительно обработанные файлы.

Решение

Убедитесь, что объявление функции совпадает со своим определением.

Даже если ваш процесс сборки позволяет эти ошибки, у вас могут быть неожиданные результаты в течение времени выполнения. Если объявление функции и определение с конфликтными прототипами существуют в вашем коде, когда вы вызываете функцию, результат может быть неожиданным.

Для аргумента переменной или функции varargs, объявите функцию, прежде чем вы вызовете его. Если вы не хотите изменять свой исходный код, можно работать вокруг этой ошибки соединения.

  1. Добавьте объявление функции в отдельном файле.

  2. Только в целях верификации, #include этот файл в каждом исходном файле при помощи опции Include (-include).

Возможная причина: конфликты от несвязанных объявлений

Вы используете то же имя идентификатора в двух несвязанных объектах. Это некоторые общие причины несвязанных объектов в том же проекте Polyspace:

  • Вы намеревались объявить объекты static так, чтобы они не имели внешнего рычажного устройства, но не использовали static спецификатор.

  • Вы объявили тот же объект в нескольких исходных файлах вместо того, чтобы поместить объявление в заголовочный файл и включая в исходных файлах.

  • Вы создали проект Polyspace из команды сборки с помощью polyspace-configure команда. Команда сборки создала несколько независимых двоичных файлов, но файлы, вовлеченные во все двоичные файлы, были собраны в одном проекте Polyspace.

Решение

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

Если ваш проект Polyspace был создан из команды сборки, и исходные файлы для независимых двоичных файлов собрались, разделите проект в модули при трассировке команды сборки. Смотрите polyspace-configure.

Возможная причина: макрозависимые определения

Определение переменной зависит от макроса, задаваемого ранее. Один исходный файл задает макрос, в то время как другой не делает, вызывая конфликты в определениях переменной.

В этом примере, file1.cpp и file2.cpp включайте заголовочный файл field.h. Заголовочный файл задает структуру a_struct это зависит от макроопределения. Только один из этих двух файлов, file2.cpp, задает макро-DEBUG. Определение a_struct в модуле перевода с file1.cpp отличается от определения в модуле с file2.cpp.

file1.cppfile2.cpp
#include "field.h"

int main()
{
    a_struct s;
    init_a_struct(&s);
    return 0;
}
#define DEBUG

#include <string.h>
#include "field.h"

void init_a_struct(a_struct* s)
{
    memset(s, 0, sizeof(*s));
}

field.h:

struct a_struct {
    int n;
#ifdef DEBUG
    int debug;
#endif
};

Когда вы открываете предварительно обработанные файлы file1.ci и file2.ci, вы видите конфликтные объявления.

file1.cifile2.ci
struct a_struct {
    int n;



};
struct a_struct {
    int n;

    int debug;

};

Решение

Избегайте макрозависимых определений. В противном случае зафиксируйте соединяющиеся ошибки. Убедитесь, что макрос или задан или не определен на всех путях, которые содержат определение переменной.

Возможная причина: ключевое слово, переопределенное как макрос

Ключевое слово переопределено как макрос, но не во всех файлах.

В этом примере, bool ключевое слово в file1.cpp, но это переопределено как макрос в file2.cpp.

file1.cppfile2.cpp
#include "bool.h"

int main()
{
    return 0;
}
#define false 0
#define true (!false)

#include "bool.h"

bool.h:

template <class T>
struct a_struct {
    bool flag;
    T t;
    a_struct() {
        flag = true;
    }
};

Решение

Будьте сопоставимы со своим использованием ключевого слова в программе. Используйте ключевое слово, заданное в стандартном заголовке библиотеки, или используйте вашу переопределенную версию.

Возможная причина: различия в упаковке структуры

#pragma pack(n) оператор изменяет выравнивание упаковки структуры, но не во всех файлах. См. также #pragma Директивы (Polyspace Code Prover).

В этом примере выравнивание упаковки значения по умолчанию используется в file1.cpp, но #pragma pack(1) оператор осуществляет выравнивание упаковки 1 байта в file2.cpp.

file1.cppfile2.cpp
int main()
{
    return 0;
}
#pragma pack(1)

#include "pack.h"

pack.h:

struct a_struct {
    char ch;
    short sh;
};

Решение

Введите #pragma pack(n) оператор в заголовочном файле так, чтобы это применилось ко всем исходным файлам, которые включают заголовок.