2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3, 4, 5, 6, 7  След.
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение07.11.2014, 11:04 
Заслуженный участник
Аватара пользователя


30/01/06
72407
bin в сообщении #927632 писал(а):
Есть книга Скотт Мейерс, Эффективное использование С++. Там много примеров безумного кода на C++.

Там как раз наиболее разумный.

(Понятие "наиболее разумный код на C++" меняется со временем :-)

-- 07.11.2014 11:14:31 --

Тьфу, я спутал с другими книгами и авторами (Саттер, книга "Эффективное программирование на C++" Кёнига и Му).

У Мейерса, конечно же, много ляпов. Впрочем, в своё время и на своём месте - он сыграл положительную роль.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение07.11.2014, 14:36 
Аватара пользователя


22/09/09

1907
EtCetera
Не думал, что окажусь адвокатом Си :-), но полагаю, что cudaMalloc не подходит под опасения из comp.lang.c FAQ Question 4.9. Вот минимальный пример ее использования из книги Сандерс и Кэндрот:
код: [ скачать ] [ спрятать ]
Используется синтаксис C
/*
 * Copyright 1993-2010 NVIDIA Corporation.  All rights reserved.
 ...
 */


#include "../common/book.h"

__device__ int addem( int a, int b ) {
    return a + b;
}

__global__ void add( int a, int b, int *c ) {
    *c = addem( a, b );
}

int main( void ) {
    int c;
    int *dev_c;
    HANDLE_ERROR( cudaMalloc( (void**)&dev_c, sizeof(int) ) );

    add<<<1,1>>>( 2, 7, dev_c );

    HANDLE_ERROR( cudaMemcpy( &c, dev_c, sizeof(int),
                              cudaMemcpyDeviceToHost ) );
    printf( "2 + 7 = %d\n", c );
    HANDLE_ERROR( cudaFree( dev_c ) );

    return 0;
}
Далее авторы отмечают:
Цитата:
Более интересно выделение памяти с помощью функции cudaMalloc(). Она очень похожа на стандартную функцию mallос (), но говорит исполняющей среде CUDA, что память должна быть выделена на устройстве. Первый аргумент - это указатель на указатель, в котором будет возвращен адрес выделенной области памяти, а второй - размер этой области. Если не считать того, что указатель на выделенную область не возвращается функцией в виде значения, то поведение ничем не отличается от malloc(), даже тип возвращаемого значения void* совпадает. Конструкция HANDLE_ERROR(), окружающая обращения, - это служебный макрос, определенный в коде, прилагаемом к книге. Когда функция возвращает ошибку, он печатает сообщение и завершает приложение с кодом EXIT_FAILURE. Хотя никто не запрещает вам использовать этот макрос и в своих программах, скорее всего, такой стратегии обработки ошибок в промышленном коде будет недостаточно.
И тут возникает тонкий, но важный момент. Своей простотой и мощью язык CUDA С во многом обязан стиранию грани между кодом для CPU и для устройства. Однако программист не должен разыменовывать указатель, возвращаемый cudaMalloc(), в коде, исполняемом CPU. Этот указатель можно передавать другим функциям, выполнять с ним арифметические операции и даже приводить к другому типу. Но ни читать, ни писать в эту область памяти нельзя.
К сожалению, компилятор не может защитить от такой ошибки. Он с радостью позволит разыменовать указатель на память устройства в коде, исполняемом CPU, потому что синтаксически этот указатель ничем не отличается от любого другого. (c.35)
Т.о. это функция низкого уровня с большими ограничениями. Как видно из примера, cudaMalloc используется совместно с cudaMemcpy для клонирования переменной с в dev_c на GPU. При столь ограниченном использовании почти невозможно практически получить баг, связанный с отсутствием контроля типов в cudaMalloc. При том, что в ядре add этот контроль производится. Сандерс и Кэндрот используют обертку (book.h):
Используется синтаксис C
static void HandleError( cudaError_t err,
                         const char *file,
                         int line ) {
    if (err != cudaSuccess) {
        printf( "%s in %s at line %d\n", cudaGetErrorString( err ),
                file, line );
        exit( EXIT_FAILURE );
    }
}
#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ ))
 
Можно сгородить более сложную. Но и в защитном программировании не надо доходить до абсурда проверяя и перепроверяя все по несколько раз. Простенький пример из другого языка:
код: [ скачать ] [ спрятать ]
Используется синтаксис Delphi
program pedant;

{$APPTYPE CONSOLE}
uses
  SysUtils;
var
  i,     // счетчик цикла
  n,     // размер последовательности
  num,   // очередное число последовательности
  sum : integer;   // сумма чисел последовательности
  average : real; // среднее арифметическое

function myDiv (x,y : integer; var myResult : real) : Boolean;
// если y<>0, то myResult=x/y и функция возвращает true
// если y=0, то функция возвращает false
begin
  Result := y<>0;
  if Result then // повторная проверка
   myResult := x/y;
end; // myDiv

begin
  writeln ('Среднее арифметическое последовательности целых чисел');
  repeat
    write ('Укажите размер последовательности: ');
    readln (n);
    if n<=0 then
     writeln ('Неправильно указан размер');
  until n>0;
  sum := 0;
  for i:=1 to n do
    begin
      write ('Укажите ',i,'-е число: ');
      readln (num);
      sum := sum + num;
    end;
  if myDiv (sum, n, average) then
   writeln ('Среднее арифметическое ', average)
  else
   writeln ('Неправильно указан размер'); // никогда не исполняется
  write ('Нажмите Ввод для выхода ...');
  readln;
end.
Всегда ли перед делением нужно проверять, что делитель не ноль? Можно подойти еще педантичнее и при вводе проверять на нечисловые символы и т.д. ... и раздуть маленькую тривиальную программку до нетривиальных размеров ;-)

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение07.11.2014, 22:25 
Заслуженный участник


28/04/09
1933
Munin
Munin в сообщении #927748 писал(а):
У Мейерса, конечно же, много ляпов.
Приведите примеры, пожалуйста. :-)

bin
bin в сообщении #927812 писал(а):
Не думал, что окажусь адвокатом Си :-), но полагаю, что cudaMalloc не подходит под опасения из comp.lang.c FAQ Question 4.9.
1. Вы так быстро переключаетесь с C на C++ и обратно, что я не успеваю за Вами. Это два разных языка, вообще говоря.
2. Вполне себе подходит. Безопасно можно приводить указатели только к void*. void** таким свойством не обладает, поэтому приведение int** $\to$ void** (используемое в примере из книжки) потенциально ведет к undefined behaviour, если sizeof(int**) != sizeof(void**) и/или отличается их бинарное представление. Корректный код в данном случае мог бы выглядеть как-то так:
Используется синтаксис C
void *dev_c_tmp;
HANDLE_ERROR( cudaMalloc( &dev_c_tmp, sizeof(int) ) );
int *dev_c = dev_c_tmp;
bin в сообщении #927812 писал(а):
При столь ограниченном использовании почти невозможно практически получить баг, связанный с отсутствием контроля типов в cudaMalloc.
О каком баге идет речь?

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение07.11.2014, 22:29 
Заслуженный участник


02/08/11
6894
EtCetera в сообщении #927972 писал(а):
в C++ необходим явный static_cast или C-style cast
Нет, это вы попутали. Это из void* в С приведения не надо, а в C++ надо. К void* в обоих языках приведение неявное.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение07.11.2014, 22:38 
Заслуженный участник


28/04/09
1933
warlock66613
warlock66613 в сообщении #927975 писал(а):
Это из void* в С приведения не надо, а в C++ надо. К void* в обоих языках приведение неявное.
Да, разумеется. Но Кристобаль Хозевич успел раньше. $\copyright$

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение07.11.2014, 22:42 
Заслуженный участник


02/08/11
6894
EtCetera в сообщении #927972 писал(а):
приведение int** $\to$ void** (используемое в примере из книжки) потенциально ведет к undefined behaviour
Ну, это очень-очень потенциально. Во всех значимых реализациях в данном случае имеется implementation-defined behavior, причём во всех имплементациях этот самый behavior одинаковый и прозрачный. Писать же код, поведение которого зависит от реализации, - древняя и священная традиция C-программеров.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение07.11.2014, 23:46 
Аватара пользователя


22/09/09

1907
EtCetera в сообщении #927972 писал(а):
1. Вы так быстро переключаетесь с C на C++ и обратно, что я не успеваю за Вами. Это два разных языка, вообще говоря.
Так и я тоже не успеваю за Вами: Вы на какой сайт мне ссылку дали?: на comp.lang.c, а не на comp.lang.cpp... такого нет, а почему? ;-)
EtCetera в сообщении #927972 писал(а):
О каком баге идет речь?
Полагаю, что о том же, о котором говорите Вы:
EtCetera в сообщении #927972 писал(а):
если sizeof(int**) != sizeof(void**)
с cudaMalloc есть единственная возможность сделать баг - указать не тот size. Выше Вы привели пример из CUDA Fast Fourier Transform library (cuFFT), где:
Используется синтаксис C
cudaMalloc((void**)&data1, sizeof(cufftComplex)*NX*NY*NZ);
cudaMalloc((void**)&data2, sizeof(cufftComplex)*NX*NY*NZ);
Я так понял, что Вы опасаетесь, нпр., такого:
Используется синтаксис C
cudaMalloc((void**)&data1, sizeof(cufftComplex)*NX*NY*NZ);
cudaMalloc((void**)&data2, sizeof(cufftComplex)*NX*NZ*NZ);
Ну так можно написать и так:
Используется синтаксис C
        int size = sizeof(cufftComplex)*NX*NY*NZ;
        cudaMalloc((void**)&data1, size);
        cudaMalloc((void**)&data2, size);
Какие проблемы? ;-)

-- Пт ноя 07, 2014 23:58:01 --

PS Хрестоматийный пример:
Используется синтаксис C
while (i=j)
вместо:
Используется синтаксис C
while (i==j)
Почему в C/C++ допустимо while (i=j), я никак понять не могу...

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 00:11 
Заслуженный участник
Аватара пользователя


30/01/06
72407
EtCetera в сообщении #927972 писал(а):
Приведите примеры, пожалуйста. :-)

Это мне его для начала раскопать надо, потом вычитать... Главный пафос Мейерса - не надо писать быдлокод как на Турбо-Паскале. Ну, в эпоху засилья такого быдлокода - оно и было полезно. Но часть конкретных советов оказалась сама неудачной, и в эпоху Саттера-Александреску - не смотрится. Но конкретики не перечислю, извините. Просто я давно оставил Мейерса за спиной, и не обращался к нему.

Мог бы, конечно, потратить на это полвыходных, но есть вещи и поинтереснее, в физическом и астрономическом разделах, например.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 09:52 
Заслуженный участник


28/04/09
1933
bin
bin в сообщении #928023 писал(а):
EtCetera в сообщении #927972 писал(а):
1. Вы так быстро переключаетесь с C на C++ и обратно, что я не успеваю за Вами. Это два разных языка, вообще говоря.
Так и я тоже не успеваю за Вами: Вы на какой сайт мне ссылку дали?: на comp.lang.c, а не на comp.lang.cpp... такого нет, а почему? ;-)
Ссылка, которую я привел, одинаково справедлива как для C, так и для C++.
bin в сообщении #928023 писал(а):
EtCetera в сообщении #927972 писал(а):
О каком баге идет речь?
Полагаю, что о том же, о котором говорите Вы:
EtCetera в сообщении #927972 писал(а):
если sizeof(int**) != sizeof(void**)
с cudaMalloc есть единственная возможность сделать баг - указать не тот size. Выше Вы привели пример из CUDA Fast Fourier Transform library (cuFFT), где:
Используется синтаксис C
cudaMalloc((void**)&data1, sizeof(cufftComplex)*NX*NY*NZ);
cudaMalloc((void**)&data2, sizeof(cufftComplex)*NX*NY*NZ);
Я так понял, что Вы опасаетесь, нпр., такого:
Используется синтаксис C
cudaMalloc((void**)&data1, sizeof(cufftComplex)*NX*NY*NZ);
cudaMalloc((void**)&data2, sizeof(cufftComplex)*NX*NZ*NZ);
Ну так можно написать и так:
Используется синтаксис C
        int size = sizeof(cufftComplex)*NX*NY*NZ;
        cudaMalloc((void**)&data1, size);
        cudaMalloc((void**)&data2, size);
Какие проблемы? ;-)
Какое отношение имеет неправильное задание размера во втором параметре cudaMalloc к
EtCetera в сообщении #927972 писал(а):
sizeof(int**) != sizeof(void**)
?
Внимательно прочитайте, пожалуйста, текст по вышеприведенной ссылке.

Munin
Munin в сообщении #928031 писал(а):
Но конкретики не перечислю, извините.
Жаль, очень жаль.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 10:09 
Заслуженный участник
Аватара пользователя


30/01/06
72407
EtCetera в сообщении #928111 писал(а):
Жаль, очень жаль.

Кажется, я второй раз отличился склерозом: возможно, мои воспоминания вообще относятся не к Мейерсу, а к Голубу.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 11:16 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Да, приношу извинения, про Мейерса это я зря.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 11:40 
Аватара пользователя


22/09/09

1907
EtCetera в сообщении #928111 писал(а):
Ссылка, которую я привел, одинаково справедлива как для C, так и для C++.
Вот именно! И везде тоже самое. Поэтому C++ воспринимается как расширение С, а не как другой язык. Аналогично Pascal и OO Pascal - это два разных языка?
EtCetera в сообщении #928111 писал(а):
Какое отношение имеет неправильное задание размера во втором параметре cudaMalloc к sizeof(int**) != sizeof(void**)? Внимательно прочитайте, пожалуйста, текст по вышеприведенной ссылке.
Прежде всего, где в CUDA-примерах Вы нашли, чтобы размер в cudaMalloc задавался через sizeof(void**)?

А текст не только прочел, но частично и процитирую:
Цитата:
To appreciate the problem with void ** more clearly, compare the situation to an analogous one involving, say, types int and double, which probably have different sizes and certainly have different representations. If we have a function
void incme(double *p)
{
*p += 1;
}
then we can do something like
int i = 1;
double d = i;
incme(&d);
i = d;
and i will be incremented by 1. (This is analogous to the correct void ** code involving the auxiliary vp.) If, on the other hand, we were to attempt something like
int i = 1;
incme((double *)&i); /* WRONG */
(this code is analogous to the fragment in the question), it would be highly unlikely to work.
Тут функция incme изменяет значение переменной, находящейся по указанной ссылке, а cudaMalloc всего лишь выделяет заказанный объем памяти на устройстве. В этом принципиальная разница. Очевидно, что целое и вещественное представляются в машине по-разному, занимают разный объем памяти, и чтобы увеличить их на единицу, действовать надо по-разному. А вот чтобы выделить память под целое и под вещественное, надо просто знать их размеры. Одни и те же ящики можно использовать для хранения как риса, так и гречки: зная объемы ящика и имеющейся крупы, можно легко определить, сколько нужно ящиков, а какого типа эта крупа (рис, гречка, перловка и т.д.), нас при этом совершенно не интересует.

(BTW Амперсанд в цитатах странно воспроизводится.)

-- Сб ноя 08, 2014 11:52:36 --

BTW мне не ответили:
bin в сообщении #927812 писал(а):
Всегда ли перед делением нужно проверять, что делитель не ноль?

bin в сообщении #928023 писал(а):
Почему в C/C++ допустимо while (i=j)


-- Сб ноя 08, 2014 11:45:29 --

Munin в сообщении #928124 писал(а):
Да, приношу извинения, про Мейерса это я зря.
И про Паскаль зря ;-)

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 11:59 
Заслуженный участник


02/08/11
6894
bin в сообщении #928023 писал(а):
Почему в C/C++ допустимо while (i=j), я никак понять не могу...
А почему оно должно быть недопустимо?

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 12:10 
Аватара пользователя


22/09/09

1907
warlock66613 в сообщении #928132 писал(а):
bin в сообщении #928023 писал(а):
Почему в C/C++ допустимо while (i=j), я никак понять не могу...
А почему оно должно быть недопустимо?
А какой смысл в while (i=j)? Явный баг. В Паскале, нпр,
Используется синтаксис Pascal
while i:=j do

недопустимо.

 Профиль  
                  
 
 Re: Книга с полным и систематичным изложением современного С++?
Сообщение08.11.2014, 12:17 
Заслуженный участник


02/08/11
6894
bin в сообщении #928145 писал(а):
А какой смысл в while (i=j)?
Как вы предлагаете формализовать отсутствие смысла разработчикам компиляторов?

-- 08.11.2014, 13:22 --

warlock66613 в сообщении #928147 писал(а):
Явный баг.
Вот обобщённый пример как "явный баг" используется в реальных программах:
Используется синтаксис C
while(c = getnextchar())
    some_string[i++] = c;

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 101 ]  На страницу Пред.  1, 2, 3, 4, 5, 6, 7  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group