LINUX.ORG.RU

Бинарник откомпилированный gcc - работает, clang - нет.

 , , ,


1

2

Учу C, читаю С.Скиену, компилирую clang-ом (больше нравится вывод в случае ошибок). Дочитал до двоичных деревьев. Ниже код

#include <stdlib.h>
#include <stdio.h>


typedef struct tree{
  int item;
  struct tree *parent;
  struct tree *left;
  struct tree *right;
} tree;


tree *search_tree(tree *l, int x);
void traverse_tree(tree *l);
int insert_tree(tree **l, int x, tree *parent);


int main(int argc, char *argv[]){
  tree *l;
  insert_tree(&l, 0, NULL);
  return 0;
}


tree *search_tree(tree *l, int x){
  if(l == NULL){
    return(NULL);
  }
  if(l->item == x){
    return(l);
  }
  if(x < l->item){
    return(search_tree(l->left, x));
  }
  else{
    return(search_tree(l->right, x));
  }
}


void traverse_tree(tree *l){
  printf("%d\n", l->item);
  traverse_tree(l->left);
  traverse_tree(l->right);
}


int insert_tree(tree **l, int x, tree *parent){
  tree *p;
  printf("step1\n");
  if(*l == NULL){
    printf("step2\n");
    p = malloc(sizeof(tree));
    p->item = x;
    p->left = p->right = NULL;
    p->parent = parent;
    *l = p;
    return 0;
  }
  if(x < (*l)->item){
    printf("step3\n");
    insert_tree(&((*l)->left), x, *l);
  }
  else {
    printf("step4\n");
    insert_tree(&((*l)->right), x, *l);
  }
  return 1;
}
При запуске программы откомпилированной gcc -std=c99 все в порядке, вижу вывод
step1
step2
При запуске программы откомпилированной clang
step1
step4
step1
Ошибка сегментирования (сделан дамп памяти)
И собственно вопрос - почему? Я криворук и не понимаю чего то? На сколько я понимаю, программа написанная правильно и по стандарту должна компилироваться и тем и другим корректно.
Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)

gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

Ответ на: комментарий от Reset

Но ведь в insert_tree передается пустой указатель, там проходит проверка на то, что он пустой и если он таки пустой, то ему присваивается указатель на результат malloc? Нет?

matroskin
() автор топика

В main:

tree *l; /* = NULL */
В insert_tree:
if(*l == NULL){

Shadow1251
()
Ответ на: комментарий от Reset
int insert_tree(tree **l, int x, tree *parent){
  tree *p;
  printf("step1\n");
  if(*l != NULL){
    printf("*l not null!!!\n");
  } else {
    printf("*l is null!!!\n");
  }
  return 0;
}

gcc (*l == NULL) true, clang (*l == NULL) false. Кто прав в итоге и как правильно сделать?

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

Undefined Behavior. Так писать просто нельзя. В неинициализированной переменной может быть что угодно. Нужно вручную инициализировать NULL-ом.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)

Ок, если в main явно инициировать tree *l = NULL, то все в порядке. На сколько я понимаю, где то в документации рассмотрен этот вопрос. Поскольку я начинающий - порекомендуйте литературу в которой это освещено. K&R читал, уважаю, купил в печатном виде.

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

Оба правы. Надо явно сделать инициализацию.

Reset ★★★★★
()

Учу C

Учи лучше C++.

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

Неявная инициализация локальных переменных - это даже если и документированная для какого-то компилятора фича, но лучше на это не полагаться, потому что на другом компиляторе или том же с другими ключами может сломаться.

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

Как советовали выше, используй gdb.
Для gcc version 4.8.2 в insert_tree значение *l приходит == 0x0, а для clang version 3.4.1 *l == 0x4004d0, т.е. случайное значение из памяти.

порекомендуйте литературу в которой это освещено.

Стандарт языка C.

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

если он таки пустой

Как уже сказали, не гарантируется, что он пустой. В Си это называется undefined behaviour. В стандарте говорится, что компилятор в ответ на это [условно] может делать, что угодно. Даже патчить твою систему патчем Бармина.

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

может делать, что угодно

Пусть тогда Folding@Home считает.

i-rinat ★★★★★
()

неинициализированные переменные - рандомный выстрел в тушку кодера из обреза. примерно так это выглядит со стороны.

MikeDM ★★★★★
()
clang test.c -std=c99 --analyze
quest ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.