# статические/динамические массивы нулевой длины

Тема в разделе "LANGS.C", создана пользователем kaspersky, 6 сен 2007.

  1. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    Код (Text):
    1. #define DATA_LEN    0   // нет данных
    2.  
    3. struct ZERO         // структура со статическим массивом нулевой длинны
    4. {
    5.     char c[DATA_LEN];   // массив нулевой длины
    6. };
    7.  
    8. main()
    9. {
    10.     // объявляем структуру с массивом нулевой длины
    11.     struct ZERO zero;
    12.    
    13.     // печатаем размер структуры ZERO и ее экземпляра zero
    14.     printf("%x %x\n", sizeof(struct ZERO), sizeof(zero));
    15.    
    16.     // присваиваем значение первой ячейке массива нулевой длины!!!
    17.     *zero.c = 0x69;
    18.    
    19.     // выводим это значение на экран
    20.     printf("0%Xh\n", *zero.c);
    21. }
    погоняйте этот пример под разными компиляторами ;)
    и загляните дизасмом ;)
     
  2. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    kaspersky
    Так это был Си. В любом случае, comeau ни в каком режиме не согласился компилировать.
     
  3. iZzz32

    iZzz32 Sergey Sfeli

    Публикаций:
    0
    Регистрация:
    3 сен 2006
    Сообщения:
    355
    IceStudent, а почему так? :derisive: В Стандарте С (§6.7.2.1) сказано, что (с некоторыми ограничениями) очень даже allowed. И именно так правильнее, imho.
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    iZzz32
    Я Си не знаю и проверял все примеры как С++, кроме последнего.
     
  5. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    Smile
    это когда char[1] -- оно ладно, один символ полюбому должен быть. а когда это массив структур? который реально может быть пустым массивом, то есть имеющим нуль элементов?
    а насчёт понятнее... это дело привычки. мне понятнее с нулём. один элемент -- это один, и почему он один, гадать можно долго. не менее долго, чем над нулём элементов ;)
    crypto
    sizeof после этого не работает.
     
  6. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    kaspersky
    А кто мешает присвоить значение хоть сотой ячейке, так память и разрушается. Был бы пойнтер ненулевой :) Вот компиляторы Басика и Паскаля могут отслеживать такие ситуации (bound error), а С и С++ не отслеживают.
     
  7. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    IceStudent
    comeau не тестировал, спасибо за сообщение. буду знать ;)
    VC, BCC, GCC - в любом режиме C/C++ компилят без ругательств и ошибок ;)
    причем, независимо от того где находится объект - на стеке или в секции данных.
     
  8. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    crypto
    > А кто мешает присвоить значение хоть сотой ячейке, так память и разрушается.
    выделить ноль байт невозможно. архитектура у PC не та ;)
    а поинтер должен быть уникальным (стандарт требует)
    следовательно, компилер просто выделяет минимальную порцию данных
    (4е байта для стека, 1 для секции данных ~16 для кучи) и усе.
    теоритически, компилер может выделить участок памяти NO_ACCESS
    и валить туда все такие указатели, но зачем ему извращаться ;)

    память не будет разрушена ;) мой код корректен. это это уже оффтопик.
    а топик был как создать массив нулевой длины. зачем - я уже объяснил.
    чтобы не возиться с кучей условных переходов, гораздо проще допустить
    чтобы DATA_LEN была равна нулю, тогда программа работает _естественнным_
    образом. функции чтения/записи позволяют принимать ноль байт в качестве
    аргумента, как и фунции копирования памяти например ;) таким образом,
    чтобы запретить программы создавать данные (в данном случае речь идет
    о вспомогательной структуре индексов, размер которой задается при
    компиляции и предусматриваетя возможность отказа от индексов для
    уменьшений размера файла). почему бы не сделать эту опцию настраиваемой
    на лету? вопрос не ко мне. программа не моя. и передо мной стояла задача
    как разрулить ситуацию с char x[DATA_LEN] при DATA_LEN == 0, не сильно
    изменив код программы и обеспечив совместимость с VC, BCC, GCC.
    что мыщъх и сделал. а теперь оказывается, что есть компиляторы,
    которые это не понимают... ну что ж... мыщъх будет знать ;)

    всем спасибо за обсуждение. и еще. на счет отслеживания границ...
    new(size) в gcc реализуется как: if (size == 0) size = 1;
    кажется я уже писал об этом. там что какая тут проверка границ?!
    new(0) реально эквивалентно new(1), тоже самое и с malloc().
     
  9. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    а вот для неверущих пример как MS VC поступает с malloc(0), там сначала прибавляется единица, а потом размер округляется по границе 10h байт в большую сторону...

    Код (Text):
    1. .text:00401B6F __heap_alloc proc near       ; CODE XREF: __nh_malloc+B↑p
    2. .text:00401B6F
    3. .text:00401B6F arg_0        = dword ptr  8
    4. .text:00401B6F
    5. .text:00401B6F              push    esi
    6. .text:00401B70          mov esi, [esp+arg_0]    ; размер выделяемой памяти
    7. ...
    8. .text:00401B87          test    esi, esi        ; выделяем ноль байт?!
    9. .text:00401B89          jnz short loc_401B8E    ; если не ноль, прыгаем
    10. .text:00401B8B          push    1           ; если ноль, увеличиваем
    11. .text:00401B8D          pop esi         ; аргумент на единицу
    12. .text:00401B8E
    13. .text:00401B8E loc_401B8E:              ; CODE XREF: __heap_alloc+1A↑j
    14. .text:00401B8E          add esi, 0Fh        ; округляем размер блока
    15. .text:00401B91          and esi, 0FFFFFFF0h ; на 10h в большую сторону
    16. .text:00401B94          push    esi         ; dwBytes
    17. .text:00401B95          push    0           ; dwFlags
    18. .text:00401B97          push    hHeap           ; hHeap
    19. .text:00401B9D          call    ds:HeapAlloc        ; выделяем блок памяти
    20. .text:00401BA3
    21. .text:00401BA3 loc_401BA3:              ; CODE XREF: __heap_alloc+16↑j
    22. .text:00401BA3          pop esi
    23. .text:00401BA4          retn
    24. .text:00401BA4 __heap_alloc endp
     
  10. PROFi

    PROFi New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2003
    Сообщения:
    690
    kaspersky

    Проще написать собственный компилятор ...

    А вообще char a[0]; // Следует ожидать один символ с индексом 0, поскольку char a[1]; определяет 2 символа. Но это с точки зрения здравого смысла, если изучать все компиляторы, то это будет напрасная потеря времени. Причина - человек задающий такие вопросы прекрсно владеет ассемблером и может сам изучить конечный код, И НИЧЕГО НЕОБЫЧНО В ЭТОМ НЕТ. Я не вижу смысла в разборе уже написанных программ, кроме как для изучения технологий в них применяемых.
    Чего стоят к примеру восстанавливающие коды Рида-Соломона, или по проще алгоритм сжатия JPEG или фрактальный, по сравнению с поиском багов в компиляторе. КОРОЧЕ ПОТЕРЯ ВРЕМЕНИ.
     
  11. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    PROFi
    Извиняюсь, это как?
     
  12. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    компилятор следует знать и уметь им пользоваться, ибо он есть рабочий инструмент. ;)
     
  13. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    PROFi
    написать свой компилятор очень сложно, особенно если ставится требование, чтобы он работал и под вынем и под никсами. мне просто было нужно создать массив нулевого размера. я нашел решение и на доступных мне компиляторах оно работало. на форум запостил мессагу, чтобы узнать, что думает по этому поводу народ и как обстоят дела с другими компиляторами. и уже обозначился по меньшей мере один компилятор, который это не переваривает. значит, нужно искать другое решение...
     
  14. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    kaspersky

    Где вы, товарищ, такую отменную ганжу берете?
     
  15. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    курите стандарт. рельно торкает
     
  16. PROFi

    PROFi New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2003
    Сообщения:
    690
    kaspersky

    В целом подход понял, только зачем народ мучать - "кто эксперементировал? ...". В таких случаях лучше приводить особенности компиляции под уже исследованными компиляторами как факт, и возможно попросить у народа проверить код сразу, а не с #21 поста :dntknw:.
    Что касается особенностей компиляторов - это извечная проблема, я думаю даже если код полностью придерживается принятого стандарта Си, все равно код не будет компилироваться всеми компиляторами, если не учитывать их особенности.

    Тему лучше вынести в топик (а еще лучше в отдельную статью) особенности универсальных (unix + windows) Си компиляторов. И попросить народ высказать свое мнение о найденных в них особенностях (я думаю их будет не один десяток). Но опять таки - жевать компиляторы, искать в них баги или особенности специально - потеря времени.
     
  17. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    _DEN_
    Это ещё фуфло вопрос... Положим, 0 байт выделять уже научились. Теперь я с нетерпением ожидаю следующих тематических исследований:
    - Как записать в массив нулевой длины данные нулевой длины
    - Как прочитать данные из массива нулевой длины
    - Как сравнить два набора данных нулевой длины
    - Какие ещё операции определены над данными нулевой длины

    PS А вот Борланд не стал лохматить бабушку и заделал такой динамический массив нулевой длины, сакральная сущность которого вполне умещается в человеческий мозг. Физически - это либо указатель на массив, если массив не пуст, либо nil, если массив имеет нулевую длину.
     
  18. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    CyberManiac
    выделять 0 байт мы не научились ;)
    стандарт, оговаривая массивы нулевой длины подчеркнул, что с ними можно делать только две вещи: получать указатель на массив и сравнивать полученный указатель с другим. что мне и было надо. так что мой код написан согласно стандарта. прикол с записью ячейки в нулевой массив это просто прикол, демонстрирующий _как_именно_ реализовано сознание нулевого массива.

    > Какие ещё операции определены над данными нулевой длины
    курите стандарт, батенька. таких оперций две. получение указателя и сравнение указателей ;)

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