2015-06-20 3 views
1

Рассмотрим следующую программу:недействительным указатель в параметре функции

#include <iostream> 
void f(void* a) 
{ 
    std::cout<<"(void*)fun is called\n"; 
    std::cout<<*(int*)a<<'\n'; 
} 
int main() 
{ 
    int a=9; 
    void* b=(int*)&a; 
    f(b); 
    return 0; 
} 

Если изменить оператор вызова функции вроде этого:

f(&b);

Он по-прежнему отлично компилируется & аварий во время выполнения. Зачем? Какова причина? Должен ли я получить ошибку времени компиляции? Поскольку правильным способом вызова функции является f (b). правильно? Кроме того, почему разрешено передавать NULL функции, параметр которой имеет тип (void *)?

Пожалуйста, исправьте меня, если я что-то упустил или что-то понял неправильно.

+2

Указатель указателя по-прежнему является указателем, поэтому он принимается за пустоту *. – Ely

+0

Вы, вероятно, хотели бы передать адрес 'a' для достижения того же:' f (&a); ' –

+5

@meet Пока комментарии EdHeals не совсем хороши, в основном он прав. Если вы не понимаете, что это делает, – deviantfan

ответ

5

Он по-прежнему отлично компилируется & во время выполнения. Зачем? Какова причина?

Потому что void* - это метод удаления всех типов безопасности и проверки типов.

Должен ли я получить ошибку времени компиляции?

Используя void* вместо правильного типа указателя int*, вы прямо говорите компилятор не сказать вам, если вы используете тип неправильно или в неопределенном способом.

Поскольку правильным способом вызова функции является f (b). правильно?

Вот где ваша функция декларации и содержания не согласен.

std::cout<<"(void*)fun is called\n"; 
    std::cout<<*(int*)a<<'\n'; 

В содержание выше означает, что указатель на int должен быть принят:

void f(void* a) 

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

2

void* может захватить любой тип указателей, не является исключением void**

+0

Почему это происходит во время выполнения? – Destructor

+0

@meet, вы интерпретируете адрес 'b' как' int * ', но' b' сам по себе является указатель, а не 'int'. – chris

1

Первый

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

Второй

Вы должны использовать преобразования типа:

void* b = static_cast<int*>(&a);

вместо преобразования с стиль вы используете:

void*b = (int*)&a; 
1

Хорошо.

В соответствии с запросом.

Не используйте указатели для void, если только вы не можете думать об этом иначе.

И ложитесь спать и подумайте еще раз.

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

Downvote me, если хотите.

Использование типов имеет роскошь, которую компилятор может проверить для вас. Например. как все взаимосвязано. Как лечить этот объект.

Но используя указатель на пустоту, вы очень много по своему усмотрению. Успехов

1

Вы не получите компиляции ошибки времени, потому что f(&b) вызовы f и передает адрес b в качестве параметра, который затем отлитого в void*. Вы получаете ошибку времени выполнения, потому что тогда вы пытаетесь наложить указатель на целое число как целое число. Но да, как заявили другие, это очень плохо.

1

Если изменить оператор вызова функции вроде этого: F (& б); Он по-прежнему компилирует штраф & сбоев во время выполнения. Зачем?

Ваша функция f(void*) примет указатель на любой тип, без жалоб. Любой указатель спокойно преобразуется в указатель пустоты. Указатель на указатель по-прежнему является указателем. Так что ваш второй случай действительно скомпилируется просто отлично. И затем он падает. Может быть.

В первом случае вы преобразовали из указателя в int указатель на возврат к указателю на int. Эти конверсии в оба конца через void* (а также через char*) должны работать. Во втором случае вы преобразовали из void** в void* в int*. Теперь вы вызываете неопределенное поведение. Все идет. На моем компьютере, мой компилятор, ваш код работает нормально. Он печатает мусор. Я был совершенно уверен, что ваш код не будет стирать мой жесткий диск, но это возможно. Все идет с неопределенным поведением. Не вызывайте неопределенное поведение.

Причина поддержки void* является исторической. Существует много старых кодов C и C++, которые используют указатели void. только причина для написания нового кода на C++, который использует указатели void, если вам нужно взаимодействовать с одной из тех старых функций, которые используют указатели void.

0

Я оказался здесь, потому что я работаю над домашним заданием, которое запрашивает ту же функциональность. Объединив каждый комментарий, это то, с чем я столкнулся. Компилятор не сбой во время выполнения.

` 
// A function that accepts a void pointer 
void f(void* a) 
{ 
    std::cout<<"(void*)fun is called\n"; 
    std::cout<< "value for a: " << *(int*)a << '\n'; 
} 


int main() { 
    int a = 9; 
    void* c = static_cast<int*>(&a); 

    int b = 3; 
    f(&b); 
    f(c); 
} 
` 
Смежные вопросы