Как меняется значение этой переменной в моем C-коде? - PullRequest
5 голосов
/ 13 февраля 2010

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

Переменные являются глобальными и имеют тип:

    int cpd;
    int nPart;

А вот соответствующий фрагмент кода, который я постепенно сократил до минимума, необходимого для создания проблемы:

    printf("\ncpd1: %d\n",cpd);

    int p;
    for(p=1;p<=nPart;p++)
    {
        printf("\ncpd2: %d\n",cpd); exit(0);
    }

... Я получаю следующий вывод:

cpd1: 17

cpd2: 0

Как, черт возьми, это возможно ?! cpd НЕ был переназначен, никакие функции не были вызваны ... все же это изменилось? КАК?!?!

Это уже давно сводит меня с ума ... ... так есть идеи?

спасибо за ваше время, Бен.

РЕДАКТИРОВАТЬ: и когда я удаляю -02 из аргументов make-файла для gcc, ОБА операторы печати говорят мне, что cpd = 0!

РЕДАКТИРОВАТЬ: Хорошо, я только что обнаружил, что переменная, которая объявляется один раз глобально, инициализируется как 4.0, а затем никогда не изменяется, теперь, по-видимому, 1.51086e-311 ... Что-то где-то очень неправильно ...

РЕДАКТИРОВАТЬ: РЕШЕНО !: У меня был массив размером 1000, который должен был быть больше 4000, и попытка записи в него повредила память вокруг него. Дело в том, что этот массив НЕ доступен где-либо рядом с этими операторами печати, однако к к обращаются в той же функции, но гораздо раньше (большая функция!). Странное расхождение между инструкциями print должно быть каким-то странным артефактом использования -O2, так как без -O2 обе распечатки cpd печатают поврежденную версию. Спасибо всем, я бы не справился с этим без вашей помощи!

Ответы [ 7 ]

15 голосов
/ 13 февраля 2010

Повреждение стекового фрейма из-за переполнения буфера является обычным объяснением этого. Вот пример:

#include <stdio.h>
#include <string.h>

int main()
{
  int cpd;
  char msg[4];
  cpd = 17;
  printf("%d\n", cpd);
  strcpy(msg, "Oops");
  printf("%d\n", cpd);
  return 0;
}

Выход:

17
0

Строковый буфер "msg" слишком короткий на один символ, терминатор строки перезаписывает значение "cpd".

Лучший способ найти причину - использовать функцию точки останова данных отладчика. Установите обычную точку останова в точке входа в функцию. Затем найдите адрес переменной "cpd" и установите для нее точку останова данных размером в байт. Отладчик остановится, как только изменится значение cpd.

Помните, что это не обязательно будет работать в оптимизированном коде, значение "cpd" может быть сохранено в регистре. Это еще одно возможное объяснение, почему его значение отличается в отдельных утверждениях.

5 голосов
/ 13 февраля 2010

Единственная возможная причина, по которой я могу думать, это то, что у вас объявлена ​​другая локальная переменная int cpd. В качестве примера я взял ваш код и немного изменил его, добавив еще одно объявление int cpd, и оставил его неинициализированным:
Обратите внимание, я должен был установить nPart = 1, чтобы цикл for выполнялся хотя бы один раз

#include <stdio.h>

int cpd;
int nPart = 1;

int main (int argc, char ** argv)
{
 printf("\ncpd1: %d\n",cpd);
 int cpd;


    int p;

    for(p=1;p<=nPart;p++)
    {
        printf("\ncpd2: %d\n",cpd); 
  break;
 }
}

Когда я запустил его, я получил следующий вывод:
cpd1: 0

cpd2: 2130567168

Как и ожидалось, глобальная переменная cpd равна 0, локальный cpd не инициализирован и может иметь практически любое 32-битное значение.

3 голосов
/ 13 февраля 2010
int main() {
    int cpd = 13;
    int nPart = 17;

    printf("\ncpd1: %d\n",cpd);

    int p;

    for(p=1;p<=nPart;p++) {
            printf("\ncpd2: %d\n",cpd);
    }

    exit(0);
}

Это компилируется и запускается с ожидаемым для меня выводом. Неправильно ли я воспроизвел ваш пример или отсутствует закрывающая скобка на конце цикла for (и включение последующего exit(0) целенаправленного?

Редактировать: предположить, что правильно включает.

3 голосов
/ 13 февраля 2010

То, что опубликовано, не может этого сделать. Единственное объяснение состоит в том, что что-то еще меняет cpd, или cpd имеет несколько экземпляров.

2 голосов
/ 13 февраля 2010

Вам необходимо опубликовать полную, минимальную, компилируемую программу. Например, следующая программа:

#include <stdio.h>
#include <stdlib.h>

int cpd = 17;
int nPart = 10;

int main(void)
{
    int p;

    printf("\ncpd1: %d\n",cpd);

    for(p=1;p<=nPart;p++)
    {
        printf("\ncpd2: %d\n",cpd); exit(0);
    }
    return 0;
}

печатает 17 дважды.

Примечание:

  • nPart инициализируется как> = 1, в противном случае цикл не выполняется ни разу.
  • Я включил stdio.h и stdlib.h для printf() и exit() соответственно.
  • Я оставил вызов exit(0); внутри цикла & mdash; не уверен, почему он у вас есть, поскольку это означает, что цикл будет выполнен не более одного раза.
0 голосов
/ 13 февраля 2010

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

Однако я сильно подозреваю, что размещенный вами фрагмент не является действительно полным (он явно не компилируется), и проблема кроется где-то в пропущенном вами коде.

0 голосов
/ 13 февраля 2010

Неинициализированная переменная может иметь любое значение, обычно в отладочной сборке она будет установлена ​​на ноль, но вы не можете полагаться на это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...