gcc. maybe-uninitialized, как узнать ветку, которую gcc считает плохой
Учти, что он может и ошибаться (_maybe_ uninitialized).
пример поправил, но у меня повторить не получилось на более простом, поэтому я там имена файлов затёр
int func(T1 &t1, T2 &t2, T3 &t3, int param)
int ret = func(t1,t2,t3);
В объявлении 4 параметра, в вызове - 3. В этом случае обычно другие ошибки валятся.
int ret = func(t1,t2,t3,i );
у структур есть конструкторы или всё так как ты описал? а то они тогда будут чем угодно
да, после конструктора по-умолчанию они и будут чем угодно. Просто я к ним обращаюсь только, если они уже не "что угодно".
судя по твоему коду ты сразу после инициализации фигачишь на них функцию... по-моему нужно привести полный код
там они и устанавливаются. Возвращаемое значение через ссылку же.
кроме t3
аа, так флаг для t3 и не ставится в функции. Добавил кусок, чтобы unused variable не было
По-моему загвоздка где-то в том, что ты компилируешь один код, а в форум постишь другой.
Вот и хочу узнать "трейс компилятора" или что-то такое. При отладке же прогеры комилятора что-то такое используют.
Почему так (через ссылки и битовую маску) коряво, — ничего лучше я не придумал. Нужно было минимизировать всё, что только можно. funс находится в другом конце приложения. Указатели - лишнее разыменовывания (хотя может это я туплю и gcc -O3 их бы убрал ? )Что за бред вообще.
Почему битовая маска а не числа 0, 1, 2, ... и свитч?
Почему возвращаешь структуры разного типа если в результате нужно из них инициализировать одно и то же как бы?
Что значит, "указатели — лишние разыменования", как ты думаешь у тебя структуры в функцию передаются, через астрал?
У тебя реально инициализация — затык по производительности? Ты вообще прогу профилировал перед тем как безумные оптимизации воротить, хотя бы чтобы проверить что они действительно делают код быстрее, если не для того, чтобы узнать, нужно ли париться вообще?
Почему гцц ругается на строчку t1.value = 10; где ты её инициализируешь, а не используешь?
у тебя if'ы внутри функции скоррелированы с if'ами после нее.
В простом случае видимо компилятор обнаруживает корреляцию и соответственно может доказать что нет использования неинициализированных переменных.
В сложном видимо корреляцию не довазывает и видит путь исполнения в котором инициализируется t1, а используется t2.
Но я не понял, что это за путь, "в котором инициализируется t1, а используется t2."
Или всё такое сложное, что компилятор решает, что переменные используются все в каких-то случаях?
PS: если имеется ввиду корреляция param и ret — весьма слабая там корреляция. часть информации берётся вообще из других функций, а не передаётся в param
в общем, я понял, да. Наверно так и есть.
Почему битовая маска а не числа 0, 1, 2, ... и свитч?
может быть несколько структур инициализировано
Почему возвращаешь структуры разного типа если в результате нужно из них инициализировать одно и то же как бы?
структуры разные.
Пример сейчас поправлю.
как ты думаешь у тебя структуры в функцию передаются, через астрал?
я думал, что будет inline.
Почему гцц ругается на строчку t1.value = 10; где ты её инициализируешь, а не используешь?
Кажется там опечатка. Не знаю, как там строчка появилась. Он ругался на то, что я использую что-то неинициализированное. Поправил.
int func(T1* &t1, T1* pt1, T2* &t2, T2* pt2, int param)
{
if(param > 0)
{
t1 = pt1;
}
else
{
t1 = NULL;
}
if(param < 10)
{
t2 = pt2
}
else
{
t2 = NULL;
}
}
T1 t1;
T1 *pt1;
T2 t2;
T2 *pt2;
double b=0;
for(int i=0;i<100;i++)
{
func(pt1, &t1,pt2, &t2, i);
if(pt1 && pt2 == NULL)
{
b = (double)pt1->value;
}
else if(pt2 && pt1 == NULL)
{
b = pt2->value;
}
else if(pt2 && pt1)
{
b = pt2->value + pt1->value;
}
// do smth with a,b,c
}
Это ещё более запутанно получается.
if(pt1 && pt2 == NULL)
upd: а, там это не самое страшное
Исходная задача: есть список действий "удалить", "создать" и т.п., в зависимости от ситуации, нужно сделать одно или несколько действий. func как раз и отвечает на вопрос, что сейчас нужно сделать. А тот код, что её вызывает должен потом эти действия сделать.
1. Язык C или C++? Если первое, то конструкторы обсуждать здесь бессмысленно; если второе, то почему нельзя хранить признак заполненности там же, где и сами значения, а не в отдельной переменной (к тому же битовой маске)?
2. Код пишется для компа или контроллера? Если для компа, то не вижу смысла сильно упираться в уменьшение занимаемой памяти и времени работы.
Мне кажется, что можно написать более элегантное решение. Какое именно - зависит от ответов на эти вопросы, а также, возможно, от еще какой-то существенной информации, которую ТС не сообщил.
PS. Строчки "ccc = t1.value;", на которую указывает gcc, в представленном коде нет.
if( pt1 && !pt2 )
или
if( pt1 != NULL && pt2 == NULL )
?
Исходная задача: есть список действий "удалить", "создать" и т.п., в зависимости от ситуации, нужно сделать одно или несколько действий. func как раз и отвечает на вопрос, что сейчас нужно сделать. А тот код, что её вызывает должен потом эти действия сделать.тоже, кстати, было бы интересно услышать, как такое на Си пишут. Мне лично только дурацкие методы в голову лезут.
А хотя там плюсы формально.
enum ActionType {...};
struct Action {
enum ActionType type;
union ActionData { ... } data;
};
#define BUF_SIZE 10
void function(struct Action* actions, int* len, int param)
{
int j = 0;
...
struct Action newAction;
// init newAction
actions[j++] = newAction;
len = j;
}
void runAction(struct Action* action)
{
// run it somehow
}
///
struct Action buffer[BUF_SIZE];
int len;
function(buffer, &len, param);
for( int i = 0; i < len; ++i ) {
runAction(buffer + i);
}
Хотя Даркгрей сейчас скажет, что у меня преждевременная инкапусляциястиль решения в мелочах, конечно, больше на c++ похоже
вот так больше похоже на C
enum ActionType {...};
struct Action {
enum ActionType type;
union { ... } data;
};
#define BUF_SIZE 10
void function(struct Action* actions, struct Action** end, int param)
{
struct Action * current = actions;
...
// init newAction
//current->type = ..;
...
current++;
*end = current;
}
void runAction(struct Action* action)
{
// run it somehow
}
///
struct Action buffer[BUF_SIZE];
struct Action * end;
function(buffer, &end, param);
for( struct Action * current = buffer; current != end; ++current) {
runAction(current);
}
1. Язык C или C++?
c++. Но используется в основном ради шаблонов
Хранить вместе со структрами - это я второй вариант сделал, В общем-то похоже. Но когда часть структуры инициализировано, а часть нет - как-то опасно выглядит.
2. Код пишется для компа или контроллера? Если для компа, то не вижу смысла сильно упираться в уменьшение занимаемой памяти и времени работы.
для компа, но это будет тред, который будет занимать 100% времени одного ядра процессора. Там надо и в кэш влезть и лишних операций не делать.
Так что это ближе к контроллеру наверно, чем к компу.
"ps". поправил.
тиль решения в мелочах, конечно, больше на c++ похожеможет быть только одно действие "создать". И количество действий ограничено. Зачем это обобщение: отдельное поле "тип".
действия обрабатываются не последовательно, а вместе.
Т.е, например, будет дейсвтие "создать" и "удалить" и у них некоторые параметры совпадают, тогда будет вызвана функция "изменить", а не 2 действия.
Некоторый действия наоборот подавляют другие действия.(например "принудительно_удалить" подавит "создать")
Есть ещё некоторое количество флагов. Некоторый действия при некоторых флагах игнорируются.
Я наоборот хочу написать так, прыжков по минимуму было, а тут лишние if'ы же на пустом месте. (if(action->type == ...
указатель+длина — вполне себе распространенная идиома.
указатель+длина — вполне себе распространенная идиома.идиома нормальная, но вот индексное обращение в C реже используется, чаще поинтеры инкрементируются
Про 100% работы на одном ядре... тут уже писали про профилировщик, напиши сначала как-нибудь _просто_, потом попрофилируй, посмотри, из-за чего тормоза, придумай более эффективный алгоритм или еще чего, если не будет устраивать имеющаяся производительность, может и так будет все ок...
Ну это все слишком мелкие тонкости, меня больше волнует интерфейс.
Просто для возврата из функции нескольких структур я сделал через ссылку и флаг, что они не нулевые. Чем это сложнее указателя и длины, а потом ещё кастов в зависимости от полей — я не понимаю,
Как тут уже подсказали, можно выделить в структуре ещё одно поле, которое будет флагом для этой структуры(поле is_null или как-то так).
Возможно тогда компилятор догадается, завтра попробую.
Хотя по сути это ведь мало отличается от битовой маски — тоже возвращение через ссылку и флаг is_null для каждого поля.
Возможно тогда компилятор догадается, завтра попробую.Ну так у тебя связанные вещи размазаны на два параметра, причем один из параметров агрегирует эти флаги для некоторого количества других параметров. Это просто объективно сложно.
Хотя по сути это ведь мало отличается от битовой маски — тоже возвращение через ссылку и флаг is_null для каждого поля.
Может быть, решается именами
enum ActionType {
AT_Create = 1 << 1,
AT_Delete = 1 << 2,
AT_Modify = 1 << 3
};
int func(CreateParams* createParams, DeleteParams* deleteParams, ModifyParams* modifyParams, int* actionsToPerform, int param)
{
*actionsToPerform = 0;
*actionsToPerform |= AT_Create;
createParams->index = 7;
return 0;
}
...
if( actionsToPerform & AT_Modify ) {
// use modifyParams
}
может быть и ок. Но здесь я реально вижу неприятности с непроинициализированностью. Где-то придется обнулять, наверное. Т.е. надо просто четко специфицировать: что делает функция со структурой, для которой не будет установлен флаг. Имхо, логично, что она ее не трогает. Тогда тебе действительно надо просто во внешнем контексте инициализировать все структуры и все будет хорошо.
Минусы этого подхода: для добавления нового типа действий придется переделывать сигнатуру функции и *все* случаи ее вызова. А еще за корректность выполнения этих действий (например, за правильный порядок) отвечает каждый вызывающий. Т.е. если изменится логика, то придется переделывать еще кучу всего. А так бы пришлось только runAction переделать и саму функцию, создающую массив действий. Исходя из этого мне проще понять код со списком действий (я просто зову вот эту функцию, а потом вон ту тем более, что это стандартный подход.
Если здесь сами действия кристально чисты и очевидна связь между ними и очевидно, что новых видов появиться не может (даже теоретически: это все вопросы понимания кода то должно быть ок, конечно.
Оставить комментарий
Phoenix
Есть функция видаона возвращает битовую маску того, какой из параметров установлен.
вызывается так
пишет
Повторить этот ворнинг на маленьком примере не получилось. Тот код, что выше компилируется без ворнингов.
Почему так (через ссылки и битовую маску) коряво, — ничего лучше я не придумал. Нужно было минимизировать всё, что только можно. funс находится в другом конце приложения.
Указатели - лишнее разыменовывания (хотя может это я туплю и gcc -O3 их бы убрал ? )
Но мне стало интересно, как узнать, что компилятор считает uninitialized может быть, т.е. что это за такая ветка.
Глазами я посмотрел, ничего не нашёл, т.е. большая вероятность, что компилятор ошибаетя.
На примере попроще - ничего не получилось. Есть подозрение, что компилятор func делает inline и ничего плохо там не надоходит.