Я запускаю следующий код через разные компиляторы:
int main()
{
float **a;
void **b;
b = a;
}
Из того, что я был в состоянии собрать, void **
это не общий указатель , который означает , что любое преобразование из другого указателя не должен составлять по крайней мере , бросить предупреждение. Тем не менее, вот мои результаты (все сделано на Windows):
- gcc - выдает предупреждение, как и ожидалось.
- g ++ - выдает ошибку, как и ожидалось (это связано с менее разрешительной типизацией C ++, верно?)
- MSVC (cl.exe) - не выдает никаких предупреждений, даже если указан / Wall.
Мой вопрос: я что-то упускаю из всего этого и есть ли какая-то конкретная причина, по которой MSVC не выдает предупреждение? MSVC делает производить предупреждение при преобразовании из void **
в float **
.
Еще одно замечание: если я заменю a = b
явным преобразованием a = (void **)b
, ни один из компиляторов не выдаст предупреждение. Я думал, что это должен быть неправильный актерский состав, так почему бы не было никаких предупреждений?
Причина, по которой я задаю этот вопрос, заключается в том, что я начал изучать CUDA и в официальном руководстве по программированию ( https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#device-memory ). следующий код можно найти:
// Allocate vectors in device memory
float* d_A;
cudaMalloc(&d_A, size);
который должен выполнять неявное преобразование в void **
for &d_A
, поскольку первый аргумент cudaMalloc
имеет тип void **
. Подобный код можно найти по всей документации. Это просто неаккуратная работа на стороне NVIDIA или я опять что-то упускаю? Поскольку nvcc
использует MSVC, код компилируется без предупреждений.
void**
это не общий указатель. Толькоvoid*
есть.(void**)
является явным приведением стиля c. Он говорит компилятору не смотреть внимательно на то, что вы делаете, и доверять вам. Это явное переопределение системы безопасности типов, и компиляторы должны принимать практически любые преобразования. Следует избегать бросков в стиле C, они слишком мощные. Используйте приведение C ++, например,static_cast
которое будет жаловаться, если вы пытаетесь сделать что-то, что не имеет смысла.Ответы:
Это назначение без приведения является нарушением ограничения, поэтому стандартный совместимый компилятор выведет предупреждение или ошибку. Однако MSVC не является полностью совместимой реализацией языка C.
Преобразование указателя с помощью приведения допускается в некоторых ситуациях. Стандарт C гласит следующее в разделе 6.3.2.3p7:
Таким образом, вы можете выполнять конвертацию между типами указателей при условии, что проблем с выравниванием нет, и вы конвертируете только обратно (если цель не a
char *
).Предположительно, эта функция разыменовывает данный указатель и записывает адрес некоторой выделенной памяти. Это будет означать, что он пытается написать так,
float *
как если бы он былvoid *
. Это не то же самое, что типичное преобразование в / изvoid *
. Строго говоря, это выглядит как неопределенное поведение, хотя и «работает», потому что современные процессоры x86 (когда они не в реальном режиме) используют одинаковое представление для всех типов указателей.источник
&d_A
что не имеют требуемого типа?