Форум программистов, компьютерный форум CyberForum.ru

Разыменование нулевого указателя - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 21, средняя оценка - 5.00
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
28.04.2011, 23:54     Разыменование нулевого указателя #1
Как вообще по стандарту ведет себя программа после разыменования нулевого указателя? Указано-ли это явно?

Просто сегодня на работе обнаружил код вроде

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
 
#define SOME_DEFINE
 
class NullClass
{
};
 
class SomeClass
{
public:
    SomeClass():t(0)
    {
    }
private:
    int t;
};
 
#ifdef SOME_DEFINE
struct some_struct
{
    typedef NullClass context_type;
    static void some_foo(int t, context_type tp)
    {
        function(t);
    }
    static void function(int t)
    {
    }
};
#else
struct some_struct
{
    typedef SomeClass context_type;
    static void some_foo(int t, context_type tp)
    {
        function(t, tp);
    }
    static void function(int t, context_type tp)
    {
    }
};
#endif
 
class MainClass
{
public:
    typedef some_struct::context_type context_type;
    MainClass(int some_param_, bool some_flg_):
        context(0), some_param(some_param_), some_flg(some_flg_)
        {
        }
    MainClass(context_type context_, int some_param_, bool some_flg_):
        context(&context_), some_param(some_param_), some_flg(some_flg_)
        {
        }
    void some_function()
    {
        some_struct::some_foo(some_param, *context);
    }
private:
    context_type* context;
    int some_param;
    bool some_flg;
};
 
int main()
{
    MainClass mc(0, false);
    mc.some_function();
}
Но там все сложнее и без этих #ifdef и т.п. не обойтись, ибо работа идет с asio. И сервер может работать либо через SSL либо без шифрования... Код кстати рабочий на работе.

Но не суть. Скомпилив на MSVS получил ошибку, что логично. Скомпилировав на gcc получил корректность! result

Как такое может быть вообще?
ЗЫ как следствие такой код ведет себя на gcc тоже прекрасно, а на msvs бросает ошибку
simple code.
Растолкуйте кто знает?
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
prazuber
108 / 108 / 3
Регистрация: 29.04.2010
Сообщений: 240
28.04.2011, 23:59     Разыменование нулевого указателя #2
Undefined behavior? Стандарт не читал, но в MSDN написано именно так.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
29.04.2011, 00:27  [ТС]     Разыменование нулевого указателя #3
PraZuBeR, Похоже да.
В комментариях

Добавлено через 27 минут
Собственно полазил по стандарту.
Пункт 1.9.4

Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. ]
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16821 / 5242 / 318
Регистрация: 30.03.2009
Сообщений: 14,118
Записей в блоге: 26
29.04.2011, 12:17     Разыменование нулевого указателя #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
А покажи, что заошибку выдаёт MSVS? Я что-то в этом коде не заметил, что ошибку должно давать

Добавлено через 3 минуты
А... тьфу ты, *context

Смысл того, что в gcc нет ошибки - из-за того, что нет реального использования значение *context. На том сайте, котором ты смотришь, gcc запускается с оптимизациями, а потому он неиспользуемое выражение попросту удалил. В MSVS при включении оптимизаций скорее всего будет то же самое

Добавлено через 2 минуты
Вот короткий пример:

C
1
2
3
4
5
6
7
int main()
{
  int x, *p;
 
  p = (int*)0;
  x = *p;
}
Переменная x нигде не используется, а следовательно "x = *p;" является мёртвым кодом и в режиме с оптимизациями компилятор его удаляет. А без оптимизаций компилятор не удаляет ничего. В итоге без оптиимзаций код ломается, а с оптимизациями проходит:

Код
$ gcc t.c
$ ./a.out
Segmentation fault
$ gcc t.c -O2
$ ./a.out
<ok>
Yandex
Объявления
29.04.2011, 12:17     Разыменование нулевого указателя
Ответ Создать тему
Опции темы

Текущее время: 07:45. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru