Перетворення в недійсні ** на різних компіляторах


9

Я використовував наступний код через різні компілятори:

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 **для &d_A, як перший аргумент cudaMallocтипу void **. Подібний код можна знайти у всій документації. Це просто неохайна робота з кінця NVIDIA чи я, знову ж, щось пропускаю? Оскільки nvccвикористовується MSVC, код компілюється без попереджень.


3
Помилки в опублікованому 3 прямому ефірі: godbolt.org/z/GQWMNo
Річард Кріттен

3
Кодові помилки для мене з MSVC. Яку версію ви використовуєте? Але так, void**це не загальний покажчик. Тільки void*є.
NathanOliver

Дякуємо за швидку відповідь! 19.24.28315 для x64 мабуть? Я раніше не дуже використовував MSVC.
КапітанProton42

2
(void**)це чіткий склад стилю c. Це заказує компілятору не дивитися уважно на те, що ви робите, і не довіряти вам. Це явне перевищення системи безпеки типу, і компілятори зобов'язані прийняти в основному будь-який вид перетворення. Слід уникати ролі в стилі C, вони занадто потужні. Використовуйте C ++ ролики, на зразок static_castяких скаржиться, якщо ви намагаєтесь зробити щось, що не має сенсу.
Франсуа Андріо

@RichardCritten неправильна мова - жодних помилок godbolt.org/z/RmFpgN C ++ cuda не потребує явних анкет, як зазвичай.
P__J__

Відповіді:


4

Я щось про щось пропускаю і чи є якась конкретна причина, чому MSVC не видає попередження? MSVC створює попередження при перетворенні з void ** в плаваючий **

Це призначення без виступу є порушенням обмеження, тому стандартний сумісний компілятор надрукує попередження або помилку. Однак MSVC не повністю відповідає C впровадженню.

Ще одна примітка: якщо я замінюю a = b явним перетворенням a = (void **) b, жоден із компіляторів не видає попередження. Я подумав, що це має бути недійсний склад, то чому б не було попереджень?

Перетворення покажчиків за допомогою кастингу дозволяється в деяких ситуаціях. Стандарт C говорить у розділі 6.3.2.3p7 наступне:

Вказівник на тип об'єкта може бути перетворений у вказівник на інший тип об'єкта. Якщо отриманий вказівник неправильно вирівняний для посиланого типу, поведінка не визначена. Інакше при повторному перетворенні результат порівнюється рівним вихідному вказівнику. Коли вказівник на об’єкт перетворюється на вказівник на тип символу, результат вказує на найнижчий адресований байт об'єкта. Послідовні прирости результату, аж до розміру об'єкта, дають покажчики на інші байти об'єкта.

Таким чином, ви можете конвертувати між типами покажчиків за умови, що проблем з вирівнюванням немає, і ви конвертуєте лише назад (якщо тільки ціль не a char *).

float* d_A;
cudaMalloc(&d_A, size);

...

Це просто неохайна робота з кінця NVIDIA чи я, знову ж, щось пропускаю?

Імовірно, ця функція полягає у перенаправлення даного вказівника та запису адреси деякої виділеної пам'яті. Це означало б, що вона намагається написати а float *так, ніби це було void *. Це не те саме, що типове перетворення в / з а void *. Строго кажучи, це виглядає як невизначена поведінка, хоча це "працює", оскільки сучасні процесори x86 (коли вони не в реальному режимі) використовують однакове представлення для всіх типів покажчиків.


@dbush Дуже інформативно, дякую! Я розумію, чому це працює, якщо працює. Все-таки, невже більшість компіляторів не видасть попередження або навіть помилку, оскільки &d_Aне має потрібного типу?
КапітанProton42

3
Будьте уважні, як ви інтерпретуєте це, можуть бути і існувати шаблонні хитрощі, якщо ви компілюєте CUDA з компілятором C ++
талонії
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.