LINUX.ORG.RU

Коммутативная операция

mv ★★★★★
()

Об этом ещё K&R писали.

bbk123 ★★★★★
()

Были случаи, когда это выглядит довольно естественным. Например, если нужно сделать lookup в коротенькую табличку, вполне можно использовать выражение вида "0112122312332334"[x]-'0', которое imho красивее записать в виде x["0112122312332334"]-'0'. Под "красивостью" в данном случае я подразумеваю, что такой код быстрее осознаётся при чтении слева направо (в первом варианте смысл цифр в строчке сильно зависит от индекса; так давайте сначала напишем индекс, а затем таблицу). Заодно совместное применение с такой необычной идиомой, как сабж, делает приём такого короткого lookup'а более запоминаемым.

alexsaa
()
Ответ на: комментарий от jtootf

> вот тебе задачка на знание C++ - как написать класс C таким образом, чтобы в процессе его создания нарушался механизм выделения памяти под объект (например, выделялось бы на 4 байта меньше чем sizeof C, что рано или поздно приводило бы к затиранию последних 4 байт объекта). перегружать new нельзя, должно одинаково работать и со стеком и с кучей

> слабо? :)


И как это сделать? Что-то ничего не гуглится...

Deleted
()
Ответ на: комментарий от alexsaa

Для тех, кто в танке, не могли бы по шагам...
Я понимаю, что "111"[1] эквивалентно 1["111"], и далее операциям над указателемями: "111" + 1 или 1 + "111".

Более того, вот такой код успешно компилируется и выдает одинаковый результат:

int main(void)
{
printf("%d\n", "111"[1]);
printf("%d\n", *("111" + 1));
printf("%d\n", 1["111"]);
}

Получается, что с точки зрения компилятора *("111" + 1) означает взять то, что лежит по указателю ("111" + 1). Но не догоняю, как компилятор распознает конструкцию "111" ??

cruz7 ★★
()
Ответ на: комментарий от cruz7

"111" - это же указатель на строку, const char *, т.е. массив эелементов типа char длинной в 4 элемента.

Deleted
()
Ответ на: комментарий от Deleted

> "111" - это же указатель на строку, const char *, т.е. массив эелементов типа char длинной в 4 элемента.

Тогда в выражении *("111" + 1) в скобках должно получиться целое число, правый операнд 1, а левый -- это адрес? Но как тогда получается результат 49?

cruz7 ★★
()
Ответ на: комментарий от cruz7

> правый операнд 1, а левый -- это адрес?

Да.

> Тогда в выражении *("111" + 1) в скобках должно получиться целое число

В скобках получается указатель на второй символ строки "111"

"111"
  ^

> Но как тогда получается результат 49?

Код символа '1' == 50. 50 - 1 == 49 == '0'.

Deleted
()
Ответ на: комментарий от cruz7

> Тогда в выражении *("111" + 1) в скобках должно получиться целое число, правый операнд 1, а левый -- это адрес? Но как тогда получается результат 49?

1. берем адрес строки "111" (адрес 1 элемента)

2. к этому адресу прибавляем 1, получаем адрес 2 элемента

3. разименовываем, получаем значение второго элемента.

Все становится очевидно при подстановки строк "121", "131".

alexru ★★★★
()
Ответ на: комментарий от Deleted

>И как это сделать? Что-то ничего не гуглится...

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

причём отладчик тут не поможет, ему сносит крышу на ура. мы подобный баг ловили две недели :)

jtootf ★★★★★
()
Ответ на: комментарий от true_admin

> но по синтаксису получается именно так как я говорю.

Не-не )) Как раз по _синтаксису_ и не получается. 1 - это не имя, а целочисленное выражение. Сишный компилятор различает типы в процессе анализа текста, и тип токена имеет решающее значение.

LamerOk ★★★★★
()
Ответ на: комментарий от legolegs

> мы подобный баг ловили две недели

ламеры, я такой же баг с libjpeg под MacOS отловил за полчаса

lester ★★★★
() автор топика
Ответ на: комментарий от lester

>ламеры, я такой же баг с libjpeg под MacOS отловил за полчаса

о, крутые кулхацкеры нарисовались. ты бы ещё в hello world его поймал, чудо

jtootf ★★★★★
()
Ответ на: комментарий от legolegs

>Кошмар. Как нашли то?

когда поняли, что именно происходит - написали минимальный proof of concept бага, и нашли два возможных варианта его заполучить при сборке. проверили дублирующие имена в объявлениях, проверили ключи сборки для разных подпроектов под разные платформы. нашли различие, собрали с изменённым jam-файлом для подпроекта, убедились что баг поборот

а искали по дампам памяти для объектов

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> о, крутые кулхацкеры нарисовались. ты бы ещё в hello world его поймал, чудо

я может и посредственный программист, но две недели на такое - это за всеми рамками

lester ★★★★
() автор топика
Ответ на: комментарий от lester

>я может и посредственный программист, но две недели на такое - это за всеми рамками

у нас 7 гигабайт исходников, полностью асинхронная компонентная система, CORBA-подобная система кодогенерации, ~50 активных потоков и две целевых архитектуры - QNX/SH4 и Win32/x86

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

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

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


ну мега круты, когда же вы работаете( и пишите гигабайты исходников - таки только исходников? ;) ), если у вас по две недели на исправление одного бага уходит? :)

lester ★★★★
() автор топика
Ответ на: комментарий от lester

>и пишите

не мы их пишем. мы волшебники - чудеса делаем

>по две недели на исправление одного бага уходит

не "по", а просто. обычно дня хватает

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> не мы их пишем. мы волшебники - чудеса делаем

ну да - гигабайты качественного кода( куда там Linux, IBM, M$ и т.п. до вас ) быстро не пишутся :)

> не "по", а просто. обычно дня хватает


можно посмотреть на страницу проекта?

lester ★★★★
() автор топика
Ответ на: комментарий от lester

ты ещё пошути тут, да

>куда там Linux, IBM, M$ и т.п. до вас

вообще-то да - им до нас, увы, далеко

>можно посмотреть на страницу проекта?

нет, конечно. могу страницу разработчика дать, надо?

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> вообще-то да - им до нас, увы, далеко

ну да - две недели на баг связанный со сборкой они не тратят :)

> нет, конечно. могу страницу разработчика дать, надо?


нет, конечно, так бы и сказал - фрилансером работаю

lester ★★★★
() автор топика
Ответ на: комментарий от lester

>две недели на баг связанный со сборкой они не тратят

ты решил поучить меня жизни, да? я растроган, сейчас заплачу

>нет, конечно, так бы и сказал - фрилансером работаю

аутстаф. разница, конечно, незаметная, но она таки есть

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

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> ты решил поучить меня жизни, да? я растроган, сейчас заплачу

и не думал

> аутстаф. разница, конечно, незаметная, но она таки есть

> то есть, фрилансером я тоже работаю. но по совсем другим проектам. с куда меньшим codebase, и с куда более приятными языками разработки


ну что ж - картина полная, больше вопросов не имею

lester ★★★★
() автор топика
Ответ на: комментарий от lester

>ну что ж - картина полная, больше вопросов не имею

happy happy joy joy

jtootf ★★★★★
()
Ответ на: комментарий от Deleted

Попытаюсь ответить чуть по-другому.

"111" - это почти то же, что и char[] { '1', '1', '1', 0 }.

Потому и "111"[1] = '1' (элемент массива). Ну а '1' == 49 (man ascii) (а не 50, кстати).

alexsaa
()
Ответ на: комментарий от true_admin

> jtootf, я правильно понимаю что проблема была в том что make clean не был сделан?

Ещё проблема могла быть в том, что какой-то отдельный модуль должен был компилироваться со специфическими опциями компиляции, которые влияли на размер структур. В этом случае make clean бы не помог.

Deleted
()
Ответ на: комментарий от true_admin

> jtootf, я правильно понимаю что проблема была в том что make clean не был сделан?

если использовались только свои классы - то судя по всему так и есть :) у меня такая ерунда была из-за того, что хедеры от libjpeg брались системные, а линковалось с libjpeg из набора paintlib, нашлось быстро( слава роб^Wдебаггерам ) - решилось еще быстрее

lester ★★★★
() автор топика
Ответ на: комментарий от true_admin

>jtootf, я правильно понимаю что проблема была в том что make clean не был сделан?

неправильно

jtootf ★★★★★
()
Ответ на: комментарий от Deleted

>какой-то отдельный модуль должен был компилироваться со специфическими опциями компиляции, которые влияли на размер структур

именно. там был набор управляемых #define'ами оптимизаций в OpenGL-модуле; в одном месте в проекте произошла рассинхронизация флагов для двух разных уровней (project и platform), которая проявлялась по-разному в x86 и SH4-сборке

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> ты просто-таки люто, бешено доставляешь. расскажи нам ещё!

я? - я сам ухахатываюсь :) такого пафоса при рассказе про элементарные вещи:

"именно. там был набор управляемых #define'ами оптимизаций в OpenGL-модуле; в одном месте в проекте произошла рассинхронизация флагов для двух разных уровней (project и platform), которая проявлялась по-разному в x86 и SH4-сборке"

я еще не встречал :)

lester ★★★★
() автор топика
Ответ на: комментарий от sf

> Какие компиляторы ломают ABI на разных уровнях оптимизации?

тут не компилятор - тут через #ifdef включалась/выключалась оптимизация в самом коде

lester ★★★★
() автор топика
Ответ на: комментарий от sf

>Какие компиляторы ломают ABI на разных уровнях оптимизации?

этот трюк работает со всеми - объектные файлы C++ не хранят информации о размере типа, она вычисляется на основании объявлений заголовочного файла

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

>>Какие компиляторы ломают ABI на разных уровнях оптимизации?
> этот трюк работает со всеми - объектные файлы C++ не хранят информации о размере типа, она вычисляется на основании объявлений заголовочного файла

Некоторые хранят размеры всех символов (как минимум gcc),
так что для отладки/страховки можно пользоваться следующим костылём:

[sf] /tmp:cat a.h 
struct C {
#ifdef I_AM_BROKEN
    char c[1024];
#endif // I_AM_BROKEN
    C() {}
};
C a_h_C_struct_sentry; // <- only for debug purpose :]

[sf] /tmp:cat a.cpp 
#define I_AM_BROKEN
#include "a.h"

[sf] /tmp:cat b.cpp 
//#define I_AM_BROKEN
#include "a.h"

[sf] /tmp:g++ a.cpp b.cpp 
/tmp/ccFhuNfW.o:(.bss+0x0): multiple definition of `a_h_C_sentry'
/tmp/ccObW0Ui.o:(.bss+0x0): first defined here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/../../../../x86_64-pc-linux-gnu/bin/ld: Warning: size of symbol `a_h_C_sentry' changed from 1024 in /tmp/ccObW0Ui.o to 1 in /tmp/ccFhuNfW.o
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: выполнение ld завершилось с кодом возврата 1

Я криво понял проблему в прошлый раз. Меня выше по теме ткнули носом.

sf ★★★
()
Ответ на: комментарий от sf

>Warning: size of symbol `a_h_C_sentry' changed

забавно. можно версию gcc?

>для отладки/страховки можно пользоваться следующим костылём:

а чем он поможет в отладке?

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

а вот утилита для анализа выделения памяти на стеке помогла бы весьма

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> >Warning: size of symbol `a_h_C_sentry' changed

> забавно. можно версию gcc?

g++-4.3.2, но вроде-бы это старая фича ld, иначе бы подобные проблемы с плюсатыми шаблонами возникали постоянно.

>>для отладки/страховки можно пользоваться следующим костылём: >а чем он поможет в отладке? Только отслеживание идентичного размера структуры во всех единицах трансляции, линкующихся в 1 бинарь.

> способов затереть четыре байта в объекте немало, backtrace от breakpoint'та на запись в область памяти различный для каждого запуска, объект имеет два десятка полей и десяток подобъектов. собственно, главная сложность - понять, что именно, и где именно произошло; анализ системы сборки - дело времени.

Valgrind запускать возможности нет? У него есть много дополнительных макросов, например, для временной пометки области памяти как read-only или недоступной вообще. Мы делаем 2 сборки проекта: с поддержкой отладки valgrind для внутренних целей и без нее.

Совсем небольшую часть проблем может детектить gcc с -fmudflap{,th} -lmudflap{,th} и дебажные макросы для gcc/glibc:-D_FORTIFY_SOURCE=N и gcc stl: -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC, но работает не на всех gcc и иногда дает кучу FP.

> а вот утилита для анализа выделения памяти на стеке помогла бы весьма

С этим всегда всё плохо. Но в принципе в рантайме можно следить и за этим. При старте программы/потока можно сохранять текущее значение стека в глобальную/локальную для потока переменную, а в интересующих местах (рекурсии всякие и просто тяжелые аллокации на стеке) проверять насколько вырос стек. В принципе получается даже условно портабельно :] Я так отслеживал объекты с доступными публичными конструкторами, которые нельзя было выделять на стеке из-за требования к их долгожительству при генерации исключений.

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

sf ★★★
()
Ответ на: комментарий от sf

>Valgrind запускать возможности нет? У него есть много дополнительных макросов, например, для временной пометки области памяти как read-only или недоступной вообще. Мы делаем 2 сборки проекта: с поддержкой отладки valgrind для внутренних целей и без нее.

есть. и valgrind'ом, и bosch'ом. но залочить область памяти можно и без его использования (хотя бы через отладочные регистры), а ошибки выделения его memcheck мониторит только в куче (у нас же посыпался стек)

>g++-4.3.2, но вроде-бы это старая фича ld, иначе бы подобные проблемы с плюсатыми шаблонами возникали постоянно

что ж, будем тестировать

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

у нас в данный момент QNX/Win32 (в перспективе - Linux); есть статический анализ исходников/бинариев (из последних в основном обработка информации от objdump), есть отладочные *alloc - но это всё, опять же, в некоторой мере помогает исследовать только кучу

очень хорошая штука Momentics в плане исследования этого дела, но увы - сугубо для QNX

jtootf ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.