Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
0 / 0 / 0
Регистрация: 20.03.2026
Сообщений: 13

Цикл for() - блок инициализации

14.04.2026, 00:38. Показов 3400. Ответов 37
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пример:

C
1
2
3
4
5
6
7
8
9
10
11
uint16_t m;
...
for (uint8_t i = 0, m = 0; i < 10; i++) {
    ...
    if(...)
        m++;
    ...
}
if(m>5) {
 
}
Какая будет переменная "m" внутри for() - та, которая создана до for() или же она создастся в for() и после цикла пропадёт?
Компилятор не ругается, но пример не работает.

По факту - то, что видно в отладчике, в этом примере переменная "m" в цикле не инициализируется и не меняется: - она имеет до for() некое значение, которое сохраняется...
Но, похоже, что это отладчик запутался в области видимости - т.е., в он вместо внутренней для for() переменной "m" (которая, видимо, всё-таки создаётся) показывает мне внешнюю по отношению к for() переменную "m"...

Если инициализацию "m" поставить перед объявлением "i", то компилятор будет ругаться.
Если инициализацию "m" сделать перед for(), то пример начинает работать...

Компилер - GCC "arm-gnu-toolchain-15.2.rel1-mingw-w64-x86_64-arm-none-eabi" с опцией "-std=c2x".
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.04.2026, 00:38
Ответы с готовыми решениями:

Вывести массив с помощью метода инициализации
Помогите вывести массив a с помощью метода инициализации,причём i меняется от 1 до n, а j от 1 до...

Разница в инициализации указателя на функцию
void f(int x) { std :: cout &lt;&lt; x; } int main() { void (*pf1)(int) = f; void...

Влият ли при инициализации цикла for инкрементирование значения
Всем привет, изменится ли переменная abc в таком примере int abc=14; int a=0; ...

37
фрилансер
 Аватар для Алексей1153
6498 / 5729 / 1133
Регистрация: 11.10.2019
Сообщений: 15,303
15.04.2026, 07:18
Студворк — интернет-сервис помощи студентам
zss, в C нет ссылок, поэтому я про указатель сказал.

Цитата Сообщение от zss Посмотреть сообщение
А вот трюк Annemesski
кстати, я обратил внимание сначала только на ::x - это доступ к глобальной переменной.

А вот дальше о_О
Цитата Сообщение от Annemesski Посмотреть сообщение
*(&x - sizeof (int))
это чистое UB, нельзя разыменовывать указатель, вышедший за край массива.
В данном случае массив состоит из одного элемента - переменной.

С++
-O0
https://onlinegdb.com/LMGohtJ0o
1 -10762399973

С++
-O3
https://onlinegdb.com/HhvaWniiY
1 231683

Добавлено через 30 минут
Цитата Сообщение от zss Посмотреть сообщение
А вот в структуре данные обязаны быть расположены рядом
тоже вовсе нет. В некоторых случаях могут быть паддинги, а при разных спецификаторах доступа поля могут быть переставлены.
Если объекты не лежат в одном массиве, так делать нельзя
1
1507 / 524 / 75
Регистрация: 22.09.2023
Сообщений: 1,654
15.04.2026, 08:46
Цитата Сообщение от S17 Посмотреть сообщение
В свою очередь замечу - чтоб попасть счётчиком в разрядность ARM, видимо, лучше использовать тип "size_t"
Специально для этого придуманы типы uint_fast8_t и uint_least8_t
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13210 / 6843 / 1824
Регистрация: 18.10.2014
Сообщений: 17,312
15.04.2026, 09:12
Цитата Сообщение от zss Посмотреть сообщение
А вот в структуре данные обязаны быть расположены рядом
??? Ничего подобного данные в структуре не должны. Данные в структуре должны быть расположены в том же порядке, в котором объявлены. Но никакого "рядом" не обещается.

Это в массиве элементы обязаны быть расположены рядом.
1
0 / 0 / 0
Регистрация: 20.03.2026
Сообщений: 13
15.04.2026, 11:44  [ТС]
Цитата Сообщение от Dushevny Посмотреть сообщение
Специально для этого придуманы типы uint_fast8_t и uint_least8_t
Да, действительно - такие есть в GNU C.
Сравнил по дизассемблеру поведение size_t, uint8_t, uint_fast8_t и uint_least8_t в качестве "объявляемого" счётчика цикла и переменной цикла стековой и статической (ключи оптимизации компилятору не указывал):

1. Разницы между size_t и uint_fast8_t я не увидел - размер берётся в 4 байта.
2. Разницы между uint8_t и uint_least8_t я не увидел - размер берётся в 1 байт.
3. Разницы uint8_t (1 байт) по отношению к size_t (4 байта) не увидел, за исключением того, что для uint8_t используются strb/ldrb вместо str/ldr, как для size_t. И для переменной цикла "static uint8_t" используется дополнительная команда перекладки байта в слово_32 "uxtb r2, r3" после r3++.
4. Из стека переменная достаётся на команду быстрее: для статической переменной сначала грузится её адрес, а потом по этому адресу она достаётся или кладётся.

C
1
2
3
4
5
6
7
8
9
void check_for(void)
{
#define type_t size_t  // uint8_t, uint_fast8_t, uint_least8_t
//  type_t m=sizeof(m);
    static type_t m=sizeof(m);
    for(type_t i=0; i<8; i++)
        m++;
#undef type_t
}
0
фрилансер
 Аватар для Алексей1153
6498 / 5729 / 1133
Регистрация: 11.10.2019
Сообщений: 15,303
15.04.2026, 11:48
S17, а зачем здесь статическая переменная ?
0
0 / 0 / 0
Регистрация: 20.03.2026
Сообщений: 13
15.04.2026, 12:45  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
S17, а зачем здесь статическая переменная ?
Чтоб понять - как с ней обращается компилятор, когда она находится не в стеке (среди локальных переменных п/программы с вероятным выравниванием на границу слов - 32/64 бита), а лежит где-то в памяти по байтовому адресу...

По дизассемблеру можно и не понять потерь в производительности из-за "невыровненного" доступа, т.к. ARM сам может его "переварить" без помощи компилятора:

The Cortex-M4 processor supports ARMv7 unaligned accesses, and performs all accesses as single, unaligned accesses. They are converted into two or more aligned accesses by the DCode and System bus interfaces.
Note
All Cortex-M4 external accesses are aligned. ...(Unaligned accesses that cross regions)
0
338 / 130 / 10
Регистрация: 19.07.2024
Сообщений: 710
15.04.2026, 13:01
Цитата Сообщение от S17 Посмотреть сообщение
Благодарю за замечание. А чем плох этот "стиль": счётчики циклов uint8_t в for() на 32-битных ARM?
Для такого локального счётчика цикла, хоть он uint хоть uint8, всё равно будет использоваться или регистр или 32-битное слово на стеке. Экономии памяти uint8 не даст. Но зато компилятор может напихать лишних команд приведения типа UXTB если будете использовать переменную цикла в каких-то выражениях. Совершенно ненужных.

Цитата Сообщение от S17 Посмотреть сообщение
В свою очередь замечу - чтоб попасть счётчиком в разрядность ARM, видимо, лучше использовать тип "size_t" (поправьте, если я неправ, т.е., ошибаюсь ).
Да, можно и так.

Добавлено через 5 минут
Цитата Сообщение от S17 Посмотреть сообщение
Разницы uint8_t (1 байт) по отношению к size_t (4 байта) не увидел
На таких простых примерах и не увидите. Разница видна когда переменная цикла используется внутри цикла в разных сложных выражениях.
И естественно - без static.
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13210 / 6843 / 1824
Регистрация: 18.10.2014
Сообщений: 17,312
15.04.2026, 17:04
Цитата Сообщение от S17 Посмотреть сообщение
А чем плох этот "стиль": счётчики циклов uint8_t в for() на 32-битных ARM?
Этот стиль плох тем, что заставляет читателя кода задавать удивленный вопрос "нафига это сделано?"

Независимо от того, на какой платформе вы работаете, в программе на С нет смысла заводить одиночные локальные переменные размера меньше чем int, когда на то нет особых причин. Переменные меньших типов имеют право на существование только для каких-нибудь специальных целей и специальных случаев (требуется особое поведение при переполнении, тип навязан внешним API, и т.д). Нет специальных требований? Тогда int или unsigned int или что-то побольше.

Цитата Сообщение от S17 Посмотреть сообщение
В свою очередь замечу - чтоб попасть счётчиком в разрядность ARM, видимо, лучше использовать тип "size_t" (поправьте, если я неправ, т.е., ошибаюсь ).
Не надо заниматься никаким "попаданием". Вам достаточно будет диапазона unsigned int? Значит используйте unsigned int. А компилятор потом сам куда надо и во что надо "попадет".
1
0 / 0 / 0
Регистрация: 20.03.2026
Сообщений: 13
15.04.2026, 18:20  [ТС]
jcxz, TheCalligrapher - Ок, соглашусь, спасибо!
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13210 / 6843 / 1824
Регистрация: 18.10.2014
Сообщений: 17,312
16.04.2026, 17:34
Цитата Сообщение от S17 Посмотреть сообщение
4. Из стека переменная достаётся на команду быстрее: для статической переменной сначала грузится её адрес, а потом по этому адресу она достаётся или кладётся.
Не понимаю, о каком "из стека" тут вообще может идти речь. Такой код будет держать локальные переменные в регистрах (а фактически весь код вообще скомпилируется "в пустоту", ибо не имеет никаких внешних эффектов).

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

То есть в большинстве случаев преимущество локальной переменной не в том, что она в стеке, а в том, что она не в памяти вообще, она - в регистре.
0
 Аватар для COKPOWEHEU
4146 / 2724 / 433
Регистрация: 09.09.2017
Сообщений: 12,067
17.04.2026, 10:53
Цитата Сообщение от S17 Посмотреть сообщение
чем плох этот "стиль": счётчики циклов uint8_t в for() на 32-битных ARM?
Не только счетчики, но и аргументы функций, да и вообще любые переменные.
Компилятор вынужден добавлять лишний код чтобы привести 32-битный регистр к указанному вами диапазону переменной. Причем переменные-то эти у вас локальные, то есть почти всегда лежат в регистрах, а там хоть 1 бит, хоть 32, расходуется все равно один регистр. Да и даже если приходится хранить на стеке - при выходе из функции он все равно сбросится и не будет расходовать память.
Цитата Сообщение от zss Посмотреть сообщение
А вот в структуре данные обязаны быть расположены рядом
Нет. __attribute__((__packed__)) не просто так придумали.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ cat main.c
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
 
typedef struct{
  uint8_t u8;
  uint16_t u16;
  uint32_t u32;
}str_t;
 
typedef struct __attribute__((__packed__)){
  uint8_t u8;
  uint16_t u16;
  uint32_t u32;
}pstr_t;
 
int main(){
  printf("%zi\t%zi\t%zi\n", offsetof(str_t, u8), offsetof(str_t, u16), offsetof(str_t, u32));
  printf("%zi\t%zi\t%zi\n", offsetof(pstr_t, u8), offsetof(pstr_t, u16), offsetof(pstr_t, u32));
}$gcc main.c -Wall -Wextra -Wpedantic
$ ./a.out 
0       2       4
0       1       3
1
Злостный нарушитель
 Аватар для Verevkin
10878 / 5817 / 1288
Регистрация: 12.03.2015
Сообщений: 26,855
17.04.2026, 11:27
COKPOWEHEU, ты специально так делаешь, чтобы никто читать код не стал, да?

0
 Аватар для COKPOWEHEU
4146 / 2724 / 433
Регистрация: 09.09.2017
Сообщений: 12,067
17.04.2026, 13:54
Там двадцать строчек, причем интерес представляют не сточки кода, а вывода на терминал.
}$gcc main.c -Wall -Wextra -Wpedantic но вот это косяк, да. Надо было добавить пустую строчку в конец.
0
0 / 0 / 0
Регистрация: 20.03.2026
Сообщений: 13
18.04.2026, 20:11  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Не понимаю, о каком "из стека" тут вообще может идти речь. Такой код будет держать локальные переменные в регистрах
В регистрах ничего не хранилось... Наверное, потому, что я не давал никаких ключей оптимизации...

Тест был в виде подпрограммы - там было 4 цикла со счётчиками и переменными цикла: size_t, uint8_t, uint_fast8_t и uint_least8_t.
И ещё таких же 4 цикла, где переменные цикла - статические.
Оптимизации нет.
Для 8ми счётчиков, хоть все они локальные внутри for(), было выделено 8 слов_32 в стеке.
Там, где счётчики цикла байтовые uint8_t или uint_least8_t к ним в то же слово_32 рядом клался байт переменной цикла uint8_t или uint_least8_t, когда она не статическая.

Все (++) делались в регистрах, но перед и после шло обращение в память, даже если на следющей операции нужен тот же счётчик для сравнения с условием завершения цикла.

Если переменная статическая, то к этим обращениям в память каждый раз добавлялись загрузки адреса этой статической переменной, по которому дальше она считывалась/записывалась.
Если переменная цикла байтовая uint8_t или uint_least8_t, то после (++) добавлялось обрезание до байта (uxtb r2, r3).

Код компилировался, но не линковался, т.к. нигде не использовался...

Пример цикла:
C
1
2
3
    static uint_least8_t sm8l=sizeof(sm8l);
    for(uint_least8_t i=0; i<8; i++)
        sm8l++;
Это компилировалось в:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   0:   b480        push    {r7}
   2:   b08b        sub sp, #44 @ 0x2c
   4:   af00        add r7, sp, #0
...
    static uint_least8_t sm8l=sizeof(sm8l);
    for(uint_least8_t i=0; i<8; i++)
  cc:   2300        movs    r3, #0              // i=0
  ce:   70fb        strb    r3, [r7, #3]        // i->@3b
  d0:   e008        b.n e4 <check_for+0xe4>
        sm8l++;
  d2:   4b0c        ldr r3, [pc, #48]   @ (104 <check_for+0x104>)   // &sm8l
  d4:   781b        ldrb    r3, [r3, #0]                            // sm8l<-*sm8l(b)
  d6:   3301        adds    r3, #1                                  // sm8l++
  d8:   b2da        uxtb    r2, r3                                  // &0xFF
  da:   4b0a        ldr r3, [pc, #40]   @ (104 <check_for+0x104>)   // &sm8l
  dc:   701a        strb    r2, [r3, #0]                            // sm8l->*sm8l(b)
    for(uint_least8_t i=0; i<8; i++)
  de:   78fb        ldrb    r3, [r7, #3]        // i<-@3b
  e0:   3301        adds    r3, #1              // i++
  e2:   70fb        strb    r3, [r7, #3]        // i->@3b
  e4:   78fb        ldrb    r3, [r7, #3]        // i<-@3b
  e6:   2b07        cmp r3, #7                  // i ? 7
  e8:   d9f3        bls.n   d2 <check_for+0xd2>
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13210 / 6843 / 1824
Регистрация: 18.10.2014
Сообщений: 17,312
18.04.2026, 20:48
Цитата Сообщение от S17 Посмотреть сообщение
В регистрах ничего не хранилось... Наверное, потому, что я не давал никаких ключей оптимизации...
Но по сгенерированному в таком режиме коду нет смысла судить о реальном положении дел. Такой код предназначен лишь для облегчения отладки.

Цитата Сообщение от S17 Посмотреть сообщение
Все (++) делались в регистрах, но перед и после шло обращение в память, даже если на следющей операции нужен тот же счётчик для сравнения с условием завершения цикла.
Ну то есть сгенерированный код был набит посторонним шумом, предназначенным для облегчения просмотра переменных в отладчике.

Ваши изначальные соображения, как я понял, были ориентированы на оценку производительности кода и/или оценку потребления памяти. Для таких целей рассматривать сгенерированный отладочный код - пустая трата времени.
1
 Аватар для COKPOWEHEU
4146 / 2724 / 433
Регистрация: 09.09.2017
Сообщений: 12,067
19.04.2026, 10:09
Цитата Сообщение от S17 Посмотреть сообщение
В регистрах ничего не хранилось... Наверное, потому, что я не давал никаких ключей оптимизации...
Да, если оптимизация отключена, компилятор будет делать множество ненужных действий. Вот только что вы этим проиллюстрировать-то хотели?
0
0 / 0 / 0
Регистрация: 20.03.2026
Сообщений: 13
20.04.2026, 00:54  [ТС]
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Да, если оптимизация отключена, компилятор будет делать множество ненужных действий. Вот только что вы этим проиллюстрировать-то хотели?
Хотел посмотреть поведение типов size_t, uint8_t, uint_fast8_t и uint_least8_t в роли счётчиков и переменных цикла.
0
2493 / 1157 / 709
Регистрация: 25.04.2016
Сообщений: 3,338
06.05.2026, 10:32
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <stdint.h>
 
int main (void) {
    uint16_t i = 2;
    {
        uint8_t i = 0;
        loop:
            if (i < 10) {
                printf("in loop i = %d\n", i);
                i++;
                goto loop;
            }
    }
    printf(" at out i = %d\n", i);
    return 0;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
06.05.2026, 10:32

Динамический массив структур - Ошибка "значение int* нельзя использовать для инициализации сущности типа TRGB"
требуется создать динамический массив структур, т.е. он не совсем динамический, просто изначально...

Как написать функцию инициализации числа из целой переменной и сохранения числа в целую переменную?
как написать функцию инициализации числа из целой переменной и сохранения числа в целую переменную?

Задание n элементу массива значения во время инициализации
Читал книгу Кочан С. - Программирование на языке С - 2007, дошел до главы с массивами. ...

Ошибка при инициализации поля структуры
При инициализации поля структуры в массиве структур вылетает ошибка. Подскажите пожалуйста, как...

Предупреждение: при инициализации целое преобразуется в указатель без приведения типа
Простой код: #include &lt;stdio.h&gt; #include &lt;string.h&gt; char *foo(); int main() { return...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
38
Ответ Создать тему
Новые блоги и статьи
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
Знание — сила: Доктрина интенциональности знаний, углубление в формулу
Hrethgir 01.08.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11957&stc=1&d=1785567302 Знаменитый афоризм Фрэнсиса Бэкона «Знание — сила» (Scientia potentia est) в массовой культуре принято понимать. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru