Инициализация массивов в C++

По крайней мере, OpenID отправляет Вас Вашему поставщику OpenID для входа в систему.
я читал блог на blogspot и существует ссылка для следования, этот блог (по-видимому, говорят мне, когда существуют newposts) сделать это, это открывается поле, просящее мое имя пользователя Gmail и пароль.

Даже предположение, что это является подлинным и не сайт фишинга - они теперь (потенциально), имеет вход в систему моего Gmail, моих документов Google, моих приложений Google - все!

5
задан Naveen 20 November 2009 в 12:11
поделиться

10 ответов

Я предполагаю инициализацию стека, потому что статические массивы инициализируются автоматически.
Вывод G ++

   char whatever[2567] = {'\0'};
   8048530:       8d 95 f5 f5 ff ff       lea    -0xa0b(%ebp),%edx
   8048536:       b8 07 0a 00 00          mov    $0xa07,%eax
   804853b:       89 44 24 08             mov    %eax,0x8(%esp)
   804853f:       c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)
   8048546:       00 
   8048547:       89 14 24                mov    %edx,(%esp)
   804854a:       e8 b9 fe ff ff          call   8048408 <memset@plt>

Итак, вы инициализируете с помощью {'\ 0'}, и вызов memset выполнен, так что да, производительность падает.

10
ответ дан 18 December 2019 в 07:29
поделиться

Если переменная является глобальной или статической, то ее данные обычно дословно сохраняются в скомпилированном исполняемом файле. Итак, ваш char arrBuffer [1024] увеличит размер исполняемого файла на 1024 байта. Его инициализация гарантирует, что исполняемый файл будет содержать ваши данные вместо 0 по умолчанию или того, что выберет компилятор. При запуске программы не требуется никакой обработки для инициализации переменных.

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

7
ответ дан 18 December 2019 в 07:29
поделиться

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

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

Например, следующий код совершенно нормален:

int main (void) {
    int a[1000];
    : :
    for (int i =0; i < sizeof(a)/sizeof(*a); i++)
        a[i] = i;
    : :
    // Now use a[whatever] here.
    : :
    return 0;
}

В этом случае это бесполезно инициализировать массив в момент его создания.

Что касается снижения производительности, это частично зависит от того, где определена ваша переменная, и частично от среды выполнения.

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

Это не предписывает, как выполняется этот второй шаг. Типичный способ - просто заставить компилятор сам создать инициализированную переменную и поместить ее в исполняемый файл так, чтобы она инициализировалась в силу того факта, что исполняемый файл загружен. Это не повлияет на производительность (очевидно, что при инициализации это повлияет на загрузку программы).

Конечно, реализация может пожелать сэкономить место в исполняемом файле и инициализировать эти переменные кодом (перед вызовом main). Это будет иметь влияние на производительность, но, вероятно, будет незначительным.

Что касается переменных с автоматической продолжительностью хранения (локальные переменные и т. Д.), Они никогда не инициализируются неявно, если вы не присвоите им что-то, так что это также приведет к снижению производительности. Под «никогда не инициализироваться неявно» я имею в виду сегмент кода:

void x(void) {
    int x[1000];
    ...
}

приведет к тому, что x [] будет иметь неопределенные значения. Но поскольку:

void x(void) {
    int x[1000] = {0};
}

может просто привести к операции типа memcpy с 1000-целым числом (более вероятно, что memset в этом случае), это, вероятно, также будет быстрым. Вам просто нужно иметь в виду, что инициализация будет происходить каждый раз, когда вызывается функция.

Это будет иметь влияние на производительность, но, вероятно, будет незначительным.

Что касается переменных с автоматической продолжительностью хранения (локальные переменные и т. Д.), Они никогда не инициализируются неявно, если вы не присвоите им что-то, так что это также приведет к снижению производительности. Под «никогда неявно инициализироваться» я подразумеваю сегмент кода:

void x(void) {
    int x[1000];
    ...
}

приведет к тому, что x [] будет иметь неопределенные значения. Но поскольку:

void x(void) {
    int x[1000] = {0};
}

может просто привести к операции типа memcpy с 1000-целым числом (более вероятно, что memset в этом случае), это, вероятно, также будет быстрым. Вам просто нужно иметь в виду, что инициализация будет происходить каждый раз, когда вызывается функция.

Это будет иметь влияние на производительность, но, вероятно, будет незначительным.

Что касается переменных с автоматической продолжительностью хранения (локальные переменные и т. Д.), Они никогда не инициализируются неявно, если вы не присвоите им что-то, так что это также приведет к снижению производительности. Под «никогда неявно инициализироваться» я подразумеваю сегмент кода:

void x(void) {
    int x[1000];
    ...
}

приведет к тому, что x [] будет иметь неопределенные значения. Но поскольку:

void x(void) {
    int x[1000] = {0};
}

может просто привести к операции типа memcpy с 1000-целым числом (более вероятно, что memset в этом случае), это, вероятно, также будет быстрым. Вам просто нужно иметь в виду, что инициализация будет происходить каждый раз, когда вызывается функция.

re никогда не инициализируется неявно, если вы не назначите им что-то, поэтому это также приведет к снижению производительности. Под «никогда неявно инициализироваться» я подразумеваю сегмент кода:

void x(void) {
    int x[1000];
    ...
}

приведет к тому, что x [] будет иметь неопределенные значения. Но поскольку:

void x(void) {
    int x[1000] = {0};
}

может просто привести к операции типа memcpy с 1000-целым числом (более вероятно, что memset в этом случае), это, вероятно, также будет быстрым. Вам просто нужно иметь в виду, что инициализация будет происходить каждый раз, когда вызывается функция.

re никогда не инициализируется неявно, если вы не назначите им что-то, поэтому это также приведет к снижению производительности. Под «никогда не инициализироваться неявно» я имею в виду сегмент кода:

void x(void) {
    int x[1000];
    ...
}

приведет к тому, что x [] будет иметь неопределенные значения. Но поскольку:

void x(void) {
    int x[1000] = {0};
}

может просто привести к операции типа memcpy с 1000-целым числом (более вероятно, что memset в этом случае), это, вероятно, также будет быстрым. Вам просто нужно иметь в виду, что инициализация будет происходить каждый раз, когда вызывается функция.

void x(void) {
    int x[1000] = {0};
}

может просто привести к операции типа memcpy с 1000-целым числом (более вероятно, что memset в этом случае), это, вероятно, также будет быстрым. Вам просто нужно иметь в виду, что инициализация будет происходить каждый раз, когда вызывается функция.

void x(void) {
    int x[1000] = {0};
}

может просто привести к операции типа memcpy с 1000-целым числом (более вероятно, что memset в этом случае), это, вероятно, также будет быстрым. Вам просто нужно иметь в виду, что инициализация будет происходить каждый раз, когда вызывается функция.

4
ответ дан 18 December 2019 в 07:29
поделиться

Чтобы ответить на ваш вопрос: это может повлиять на производительность. Возможно, что компилятор мог обнаружить, что значения массива не использовались, и просто не использовать их. Это возможно.

Я лично считаю, что это вопрос личного стиля. У меня возникает соблазн сказать: оставьте его неинициализированным и используйте инструмент, похожий на Lint, чтобы сообщить вам, используете ли вы его неинициализированным, что, безусловно, является ошибкой (в отличие от использования значения по умолчанию и отсутствия уведомления, что также ошибка, но тихая).

0
ответ дан 18 December 2019 в 07:29
поделиться

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

0
ответ дан 18 December 2019 в 07:29
поделиться

Измерение!

#include <stdio.h>
#include <time.h>

int main(void) {
  clock_t t0;
  int k;

  t0 = clock();
  for (k=0; k<1000000; k++) {
    int a[1000];
    a[420] = 420;
  }
  printf("Without init: %f secs\n", (double)(clock() - t0) / CLOCKS_PER_SEC);

  t0 = clock();
  for (k=0; k<1000000; k++) {
    int a[1000] = {0};
    a[420] = 420;
  }
  printf("   With init: %f secs\n", (double)(clock() - t0) / CLOCKS_PER_SEC);

  return 0;
}
$ gcc measure.c
$ ./a.out
Without init: 0.000000 secs
   With init: 0.280000 secs
$ gcc -O2 measure.c
$ ./a.out
Without init: 0.000000 secs
   With init: 0.000000 secs
2
ответ дан 18 December 2019 в 07:29
поделиться

И почему вы заботитесь о преимуществах производительности, сколько производительности вы получите, не инициализируя ее, и действительно ли это больше, чем время, сэкономленное во время отладки из-за указателей на мусор.

-2
ответ дан 18 December 2019 в 07:29
поделиться

I consider that it is a bad advice to require all variables to be default initialized at the time of declaration. In most cases it is unnecessary and carries performance penalty.

For example, I often use the code below to convert a number to a string:

char s[24];
sprintf(s, "%d", int_val);

I won't write:

char s[24] = "\0";
sprintf(s, "%d", int_val);

Modern compilers are able to tell if a variable is used without being initialized.

0
ответ дан 18 December 2019 в 07:29
поделиться

Your variables should be initialized to a meaningful value. Blindly and naively setting everything to zero isn't much better than leaving it uninitialized. It might make invalid code crash, instead of behaving unpredictably, but it won't make the code correct.

If you just naively zero out the array when creating it just to avoid uninitialized variables, it is still logically uninitialized. it doesn't yet have a value that is meaningful in your application.

If you're going to initialize variables (and you should), give them values that make sense in your application. Does the rest of your code expect the array to be zero initially? If so, set it to zero. Otherwise set it to some other meaningful value.

Or if the rest of your code expects to write to the array, without first reading to it, then by all means leave it uninitialized.

0
ответ дан 18 December 2019 в 07:29
поделиться

Лично я против инициализации массива при создании. Рассмотрим следующие два фрагмента кода:

char buffer[1024] = {0};
for (int i = 0; i < 1000000; ++i)
{
  // Use buffer
}

против

for (int i = 0; i < 1000000; ++i)
{
  char buffer[1024] = {0};
  // Use buffer
}

В первом примере зачем беспокоиться об инициализации буфера, если во второй раз буфер цикла больше не инициализирован 0? Мое использование буфера должно работать без его инициализации для всех, кроме первой итерации. Все, что делает инициализация, - это отнимает время, раздувает код и скрывает ошибки, если обычно я прохожу цикл только один раз.

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

Я подозреваю, что в наши дни у большинства компиляторов есть опции для заполнения неинициализированных переменных значениями, отличными от 0. Мы запускаем все наши отладочные сборки таким образом, чтобы помочь обнаружить использование неинициализированных переменных, а в режиме выпуска мы отключаем эту опцию, чтобы переменные действительно не инициализировались. Как сказал Шервуд Ху, некоторые компиляторы могут вводить код, чтобы помочь обнаружить использование неинициализированных переменных.

Изменить: В приведенном выше коде я инициализирую буфер значением 0 (не символом '0'), что эквивалентно его инициализации с помощью '\ 0'.

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

char buffer[1024] = {0};
for (int i = 0; i < 1000000; ++i)
{
  // Buffer is 0 initialized, so it is fine to call strlen
  int len = strlen (buffer);
  memset (buffer, 'a', 1024);
}

При первом прохождении цикла буфер инициализируется значением 0, поэтому strlen вернет 0. Во второй раз в цикле буфер больше не инициализируется значением 0 и фактически не содержит ни одного символа 0, поэтому поведение strlen не определено.

Поскольку вы согласились со мной, что если буфер инициализирован, перемещение буфера внутри цикла не рекомендуется, и я показал, что его инициализация вне цикла не обеспечивает защиты, зачем инициализировать это вообще?

0
ответ дан 18 December 2019 в 07:29
поделиться