C++ и linux (частые ошибки новичков при сборке программ на C/C++ в Linux)

Модератор: Модераторы разделов

Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C++ и linux

Сообщение drBatty »

Dunris писал(а):
23.08.2009 22:53
Еще не разобрался где необходимо объявление (например для объекта а) типа char a, а где использовать указатель char * a. Купил книгу "Программирование в Linux", там в основном практические примеры программ. И довольно часто практикуется char * a. Вот и я наверное использовал указатель, поэтому switch ругался...
P.S. а можно, если Вам не трудно, кратко рассказать о разнице в определениях? blush.gif Извиняюсь, получается как-то нагловато blush.gif

это объявление того факта, что какая-то область памяти доступная для кодера (1 байт, от -128 до +127) теперь называется a.
К этой области можно обращаться, например:

Код: Выделить всё

a = 2 * 2;

или распечатать

Код: Выделить всё

printf("%d\n", a);

Но можно обратится не прямо (a), а косвенно, по её адресу:

Код: Выделить всё

char *p = &a;

p - это тоже псевдоним адреса, но этот адрес указывает на память, в которой лежит другой адрес, размер этой области обычно 4 байта. Что-бы добраться до байта a, нужно прочитать адрес из p, а потом прочитать число по прочитанному адресу:

Код: Выделить всё

char x = *p;

Операция * здесь называется "разименование", мы берём не саму p, а то, на что указывает содержимое p.

ЗЫЖ
a - означает "содержимое памяти, которое названо a", а вот &a - означает - "взять адрес памяти, который мы называем 'a'"
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Dunris
Сообщения: 295
Статус: ...
ОС: Archlinux

Re: C++ и linux

Сообщение Dunris »

Операция * здесь называется "разименование", мы берём не саму p, а то, на что указывает содержимое p.
ЗЫЖ
a - означает "содержимое памяти, которое названо a", а вот &a - означает - "взять адрес памяти, который мы называем 'a'"

Спасибо, с конкретно этим примером все ясно :)
Но, если точнее, я чуть-чуть другое имел ввиду. Вы создали конкретную переменную a, затем создали указатель на нее, по которому можно к этой конкретной переменной и обращаться(указатель на адрес переменной a).
А вот пример работающего кода из книги:

Код: Выделить всё

#include <stdio.h>

 int main (int argc, char [b]**[/b] argv)
 {
        char [b]*[/b] value;
        if (argc < 2) {
               fprintf (stderr, "Usage: myenv2 <variable>\n");
               return 1;
        }

        value = (char*) getenv (argv[1]);
        if (value == NULL)
               printf ("%s not found\n", argv[1]);
        else
               printf ("%s=%s\n", argv[1], value);

        return 0;
 }

Здесь указатели используются как-то иначе... Или мне только кажется, что иначе. То есть char * value - указатель на область памяти типа char, с этим ясно. Но по идее, чтобы присвоить значение этой области, необходимо обратиться к указателю *value. Здесь же присваивают значение как бы указателю, хотя этого сделать, если я не ошибаюсь, нельзя. Также интересен аргумент функции main, запись вида char ** argv. Да и в целом интересна роль указателей в этой программе.
И ведь код работает, значит программа безошибочна, но я ее неправильно воспринимаю.
Если короче сформировать: когда целесообразно использовать объявление char a (если больше одного символа, соответственно char a[]), а когда нужно, как описано выше, использовать указатель char * a.
P.S. Сорри, сам знаю, что глупый вопрос, однако ж не совсем разобрался :blush:
Спасибо сказали:
Аватара пользователя
Crazy
Сообщения: 862
Статус: Адепт Дзен.
ОС: Mint, Win7.

Re: C++ и linux

Сообщение Crazy »

То есть char * value - указатель на область памяти типа char, с этим ясно

Тип указателя говорит компилятору как нужно обрабатывать область памяти, на которую ссылается данный указатель.
Массив в C/C++ это просто кусок памяти, содержащий элементы одного типа. Поэтому для обращения к массиву достаточно знать адрес первого его элемента.
char ** argv
Если запускать a.out строка1 строка2, то argv[1] начало строки1, argv[2] начало строки2.
Но по идее, чтобы присвоить значение этой области, необходимо обратиться к указателю *value.

в строчке

Код: Выделить всё

char *value;

объявляется указатель, но области памяти за этим указателем нет.

Код: Выделить всё

value = (char*) getenv (argv[1]);

Здесь инициализация value, если что то передали, то возвращает указатель на начало строки.

Если короче сформировать: когда целесообразно использовать объявление char a (если больше одного символа, соответственно char a[]), а когда нужно, как описано выше, использовать указатель char * a.

В общем случае, за указателем может скрываться все что угодно(массив, список и т.д.) Использовать нужно тогда, когда он нужен.

Desipere in loco
Спасибо сказали:
Аватара пользователя
Dunris
Сообщения: 295
Статус: ...
ОС: Archlinux

Re: C++ и linux

Сообщение Dunris »

Crazy писал(а):
24.08.2009 22:17
В общем случае, за указателем может скрываться все что угодно(массив, список и т.д.) Использовать нужно тогда, когда он нужен.

Спасибо:) В общих чертах понял, чтобы понять полностью еще почитаю нужной литературы:)
Спасибо сказали:
Аватара пользователя
Rootlexx
Бывший модератор
Сообщения: 4456
Статус: GNU generation
ОС: Debian GNU/Linux

Re: C++ и linux

Сообщение Rootlexx »

Dunris писал(а):
24.08.2009 20:14
То есть char * value - указатель на область памяти типа char, с этим ясно. Но по идее, чтобы присвоить значение этой области, необходимо обратиться к указателю *value. Здесь же присваивают значение как бы указателю, хотя этого сделать, если я не ошибаюсь, нельзя.

Указатель — это та же переменная, просто она содержит число, однозначно отображаемое на адрес памяти. Мы можем как изменять данные в этой области (используя оператор «*»), так и изменять сам этот адрес, после чего указатель будет направлять на другую область памяти.
«char **argv» — здесь argv — это указатель на указатель. Как и сказал Crazy, для обращения к массиву достаточно знать адрес начала области памяти, где этот массив располагается. С помощью argv можно читать аргументы командной строки, переданные в программу, но что такое эти аргументы? — это строки, то есть массивы символов типа char, и эти массивы сами объединены в массив, то есть получается двумерный массив — матрица. Поэтому и «двойной» указатель.
Указатели на самом деле очень удобны. Они позволяют добиться большей гибкости блокам вашей программы. Кроме очевидных случаев вроде передачи массива с помощью них создаются связанные списки (наверное, вы до этого ещё не дошли, но когда дойдёте, поймёте :)) и многое другое. Передать параметр функции и позволить ей его изменять можно только с помощью указателя (явно или неявно). Или, к примеру, у вас есть несколько целочисленных переменных, и в зависимости от значения некоторого параметра вы должны выбрать одну из них и проделать над ней определённые действия (одинаковые для всех этих переменных). С помощью указателей это можно сделать легко и красиво:

Код: Выделить всё

int32_t *some_var_p, var_1, var_2, var_3;
switch (var_index) {
    case VAL_1:
        some_var_p = &var_1;
        break;
    case VAL_2:
        some_var_p = &var_2;
        break;
    case VAL_3:
        some_var_p = &var_3;
}
— и далее все операции проводить уже по указателю.
Указателями можно пользоваться вообще без наличия обычных переменных. Разумеется, для того, чтобы «направить» указатель на какую-то область памяти, эта область должна прежде существовать. Это автоматически верно для переменной, но можно выделить память и вручную, используя функцию malloc:

Код: Выделить всё

int *some_var_p = malloc(sizeof(int));
— sizeof возвращает размер, в данном случае — 4 (байта). Тем самым будет выделена область размером 4 байта, и возвращён указатель на неё. В дальнейшем с этой областью можно спокойно работать. Когда эта область перестаёт быть нужна (при выходе из функции, например, или по завершении программы), выделенную память можнонужно освободить:

Код: Выделить всё

free(some_var_p);

Создание массива:

Код: Выделить всё

int *int_array = malloc(sizeof(int) * num_elements);
— теперь к элементам массива можно обращаться по индексу, как вы привыкли. «*» в параметрах malloc — это операция умножения :).
Как видите, количество элементов создаваемого массива не задаётся заранее, а может быть вычислено в процессе исполнения программы, что позволяет, во-первых, не гадать, какой же массив нужно делать, чтобы в него гарантированно поместились все передаваемые данные, а во-вторых, экономить память, не выделяя под массив больше памяти, чем нужно в данном конкретном случае.
Не забывайте освобождать память:

Код: Выделить всё

free(int_array);
Спасибо сказали:
Аватара пользователя
Dunris
Сообщения: 295
Статус: ...
ОС: Archlinux

Re: C++ и linux

Сообщение Dunris »

Большое спасибо:) Теперь ясно, но я все равно еще вернусь к чтению вашего поста, когда буду более подготовлен:)
Спасибо сказали:
Аватара пользователя
intelfx
Сообщения: 12
ОС: Arch Linux

Re: C++ и linux

Сообщение intelfx »

Здравствуйте!
У меня тоже есть проблемы с компиляцией программ в linux. Есть написанная для windows (в школе) и отлаженная программа, считающая простые числа, делители etc...

Код:

#include <assert.h> #include <stdio.h> #include <strings.h> #include <stdlib.h> int makePlainsTable (int lim, int* output); int getDividers (int src, int* output, bool only_simple_divs, const int* input, int inputlen); int getDivLayout (int src, int* output, const int* input, int inputlen); int main() { int lim = 0; bool only_simple_divs = 0; printf ("Enter src value and should I make only simple divs (0 or 1)?\n"); scanf ("%d%d", &lim, &only_simple_divs); assert (lim); int* ptable = new int [lim]; int* dtable = new int [lim]; int* ltable = new int [lim]; int ptlen = makePlainsTable (lim, ptable); int dtlen = getDividers (lim, dtable, only_simple_divs, ptable, ptlen); int ltlen = getDivLayout (lim, ltable, ptable, ptlen); printf ("\nPrinting simple values from 0 to %d\n", lim); for (int i = 0; i < ptlen; i++) printf ("%7d ", ptable [i]); printf ("\nPrinting dividers for %d\n", lim); for (int i = 0; i < dtlen; i++) printf ("%7d ", dtable [i]); //printf ("\nPrinting layout for %d", lim); getchar(); delete [] ptable; ptable = 0; delete [] dtable; dtable = 0; } int printDivLayout (const int* input, int inputlen) { int c_div = input[0]; int div_c = 0; int value = 1; for (int i = 0; i < inputlen; i++) value *= input [i]; printf ("%d =", value); for (int i = 0; i < inputlen; i++) { if (input [i] == c_div) div_c++; else { printf (" %d^%d ", c_div, div_c); putchar ('*'); c_div = input [i]; div_c = 1; } if ( (i + 1) == inputlen) //last value isn't printed printf (" %d^%d", c_div, div_c); } } int getDivLayout (int src, int* output, const int* input, int inputlen) { assert (src > 1); int part = src; int count = 0; while (part != 1) { for (int i = 0; i < inputlen; i++) { int cur_value = input [i]; if ( !(part % cur_value) ) { part /= cur_value; output [count++] = cur_value; break; } } } return count; } int getDividers (int src, int* output, bool only_simple_divs = 0, const int* input = 0, int inputlen = 0) { printf ("Calculating dividers for src = %d\n\n", src); int count = 0; int cur_value = 0; int for_limit = 0; for_limit = (only_simple_divs) ? inputlen : (src / 2 + 1); for (int i = 0; i < for_limit; i++) { cur_value = (only_simple_divs) ? input [i] : i; if (cur_value < 2) continue; if ( !(src % cur_value) ) output [count++] = cur_value; } return count; } int makePlainsTable (int src, int* output) { assert (src); src++; bool* a = new bool [src]; for (int i = 0; i < src; i++) a[i] = true; a[0] = false; a[1] = false; int csv = 2; //current simple value int lrv = 4; //limit of right values printf ("Calculating table for src = %d\n\n", src); do { for (int i = (csv * 2); i < src; i += csv) a[i] = false; //cut values that are multiplies of csv for (int i = csv + 1; i < lrv; i++) if (a[i]) { csv = i; break; } lrv = csv * csv; if (lrv > src) lrv = src; } while (lrv < src); int count = 0; for (int i = 0; i < src; i++) if (a[i]) output[count++] = i; delete [] a; a = 0; return count; }

Здесь (по сравнению с виндовым вариантом) был убран #include <conio.h> по причине отсутствия такового в linux, и getch() был заменен на getchar().

При компиляции линкер ругается следующим образом:

Код:

intelfx@intelfx-desktop:~/dp/cpp/FXLib$ gcc -v Используются внутренние спецификации. Целевая архитектура: i486-linux-gnu Параметры конфигурации: ../src/configure -v --with-pkgversion='Ubuntu 4.3.3-5ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Модель многопоточности: posix gcc версия 4.3.3 (Ubuntu 4.3.3-5ubuntu4) intelfx@intelfx-desktop:~/dp/cpp/FXLib$ gcc math.cpp math.cpp: In function ‘int main()’: math.cpp:19: предупреждение: формат ‘%d’ предполагает тип ‘int*’, но аргумент 3 имеет тип ‘bool*’ /tmp/ccGZHJST.o: In function `makePlainsTable(int, int*)': math.cpp:(.text+0x1a4): undefined reference to `operator new[](unsigned int)' math.cpp:(.text+0x2b0): undefined reference to `operator delete[](void*)' /tmp/ccGZHJST.o: In function `main': math.cpp:(.text+0x420): undefined reference to `operator new[](unsigned int)' math.cpp:(.text+0x431): undefined reference to `operator new[](unsigned int)' math.cpp:(.text+0x442): undefined reference to `operator new[](unsigned int)' math.cpp:(.text+0x547): undefined reference to `operator delete[](void*)' math.cpp:(.text+0x55f): undefined reference to `operator delete[](void*)' /tmp/ccGZHJST.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0' collect2: выполнение ld завершилось с кодом возврата 1
Спасибо сказали:
Аватара пользователя
Portnov
Модератор
Сообщения: 1786
Статус: Матёрый линуксоид
ОС: Debian testing/unstable

Re: C++ и linux

Сообщение Portnov »

Хм, забавно. Вы же сами в соседней теме ответили, чем gcc отличается от g++ :)
Работа: Ubuntu 9.10
Дом: Debian testing/unstable и на всякий случай winxp в virtualbox.
Для разнообразия: моя домашняя страница -http://iportnov.ru
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: C++ и linux

Сообщение t.t »

drBatty писал(а):
24.08.2009 11:13
это объявление того факта, что какая-то область памяти доступная для кодера (1 байт, от -128 до +127) теперь называется a.
Насчёт "от -128 до +127" не совсем верно. Это зависит от умолчаний конкретного компилятора и ключей сборки. Там, где нужно обращаться с типом char как с числовыми значениями, лучше всегда явно указывать signed char или unsigned char.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: C++ и linux

Сообщение t.t »

Rootlexx писал(а):
25.08.2009 03:15

Код: Выделить всё

int *some_var_p = malloc(sizeof(int));
— sizeof возвращает размер, в данном случае — 4 (байта). Тем самым будет выделена область размером 4 байта, и возвращён указатель на неё.
Поправка: 4 байта на 32-разрядных архитектурах. Для того ведь и используется здесь sizeof(int), а не явное указание 4, чтобы обеспечить переносимость. Скажем, при сборке 16-разрядным компилятором sizeof(int)==2.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C++ и linux

Сообщение drBatty »

t.t писал(а):
30.09.2009 11:44
Насчёт "от -128 до +127" не совсем верно. Это зависит от умолчаний конкретного компилятора и ключей сборки. Там, где нужно обращаться с типом char как с числовыми значениями, лучше всегда явно указывать signed char или unsigned char.

да. это для примера числа. обычно они такие, но в данной конкретной системе конечно возможны и другие значения.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
DiIvPa
Сообщения: 7
ОС: Linux Debian Etch

Re: C++ и linux

Сообщение DiIvPa »

У меня вопрос. Есть массив int ibuf[32]; (т.е. 32*4 bytes) и есть указатель на него int *pp; И вот мне понадобилось с областью
данных ibuf поработать как с unsigned short sbuf[64];(64*2 bytes),
т.е. надо определить указатель unsigned short *p; Как это сделать ?
(Добавлю, что в fortran я бы просто использовал операцию Equivalence (ibuf, sbuf) и все). Заранее благодарен за помощь.
Спасибо сказали:
Аватара пользователя
Portnov
Модератор
Сообщения: 1786
Статус: Матёрый линуксоид
ОС: Debian testing/unstable

Re: C++ и linux

Сообщение Portnov »

unsigned short * sbuf = (unsigned short*) ibuf;

?
Работа: Ubuntu 9.10
Дом: Debian testing/unstable и на всякий случай winxp в virtualbox.
Для разнообразия: моя домашняя страница -http://iportnov.ru
Спасибо сказали:
DiIvPa
Сообщения: 7
ОС: Linux Debian Etch

Re: C++ и linux

Сообщение DiIvPa »

Portnov
Сработало, спасибо. Кстати, я тоже родом из Магнитогорска.
Спасибо сказали:
Аватара пользователя
Crazy
Сообщения: 862
Статус: Адепт Дзен.
ОС: Mint, Win7.

Re: C++ и linux

Сообщение Crazy »

Portnov писал(а):
11.01.2010 14:33
unsigned short * sbuf = (unsigned short*) ibuf;

?

Старым дедовским способом в стиле С.
http://alenacpp.blogspot.com/2005/08/c.html

Desipere in loco
Спасибо сказали:
DiIvPa
Сообщения: 7
ОС: Linux Debian Etch

Re: C++ и linux

Сообщение DiIvPa »

Crazy писал(а):
11.01.2010 16:57
Portnov писал(а):
11.01.2010 14:33
unsigned short * sbuf = (unsigned short*) ibuf;

?

Старым дедовским способом в стиле С.
http://alenacpp.blogspot.com/2005/08/c.html

Ну и как бы это должно быть по современному C++ ? Так что ли ?
unsigned short *sbuf=const_cast<int*> (ibuf);
error: cannot convert 'int*' to 'short unsigned int*' in initialization
Или как ? Заранее спасибо.
Спасибо сказали:
Аватара пользователя
Crazy
Сообщения: 862
Статус: Адепт Дзен.
ОС: Mint, Win7.

Re: C++ и linux

Сообщение Crazy »

DiIvPa писал(а):
13.01.2010 16:44
Crazy писал(а):
11.01.2010 16:57
Portnov писал(а):
11.01.2010 14:33
unsigned short * sbuf = (unsigned short*) ibuf;

?

Старым дедовским способом в стиле С.
http://alenacpp.blogspot.com/2005/08/c.html

Ну и как бы это должно быть по современному C++ ? Так что ли ?
unsigned short *sbuf=const_cast<int*> (ibuf);
error: cannot convert 'int*' to 'short unsigned int*' in initialization
Или как ? Заранее спасибо.

Так пробовал?

Код: Выделить всё

unsigned short *buff = reinterpret_cast<unsigned short*>(arr1);

Desipere in loco
Спасибо сказали:
DiIvPa
Сообщения: 7
ОС: Linux Debian Etch

Re: C++ и linux

Сообщение DiIvPa »

Portnov писал(а):
11.01.2010 14:33
unsigned short * sbuf = (unsigned short*) ibuf;

Crazy писал(а):
13.01.2010 22:18
Так пробовал?

Код: Выделить всё

unsigned short *buff = reinterpret_cast<unsigned short*>(arr1);

Так работает. Спасибо. Но вот чем этот код лучше, чем старый дедовский код ? Тем более по указанной Вами ссылке написано:
"Самое нахальное приведение типов. Не портируемо, результат может быть некорректным, никаких проверок не делается." и т.д.
Хотелось бы понять разницу.
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: C++ и linux

Сообщение RasenHerz »

DiIvPa писал(а):
14.01.2010 11:21
Так работает. Спасибо. Но вот чем этот код лучше, чем старый дедовский код ? Тем более по указанной Вами ссылке написано:
"Самое нахальное приведение типов. Не портируемо, результат может быть некорректным, никаких проверок не делается." и т.д.
Хотелось бы понять разницу.

Считается что программист здесь лучше понимает что к чему и компилятору не стоит вмешиваться.
Спасибо сказали:
DiIvPa
Сообщения: 7
ОС: Linux Debian Etch

Re: C++ и linux

Сообщение DiIvPa »

RasenHerz писал(а):
14.01.2010 11:52
DiIvPa писал(а):
14.01.2010 11:21
Так работает. Спасибо. Но вот чем этот код лучше, чем старый дедовский код ? Тем более по указанной Вами ссылке написано:
"Самое нахальное приведение типов. Не портируемо, результат может быть некорректным, никаких проверок не делается." и т.д.
Хотелось бы понять разницу.

Считается что программист здесь лучше понимает что к чему и компилятору не стоит вмешиваться.

А в старом "дедовском" способе разве не так ? Читаем на http://alenacpp.blogspot.com/2005/08/c.html :
"Что делает приведение типов в стиле С: пытается использовать static_cast, если не получается, использует reinterpret_cast. Далее, если нужно, использует const_cast ."
т.е. получается то же самое ?
Спасибо сказали:
Аватара пользователя
Portnov
Модератор
Сообщения: 1786
Статус: Матёрый линуксоид
ОС: Debian testing/unstable

Re: C++ и linux

Сообщение Portnov »

Приведение типов в C - это "трактуй вот этот указатель как указатель на unsigned short", такая директива уровнем не намного выше ассемблера. Приведённый синтаксис из плюсов использует концепции более высокого порядка (вон, даже шаблоны, похоже - но это я только по синтаксису сужу, сути не знаю)... Сводятся они, исессна, к одному и тому же - ибо это одно и то же по спецификации.
Работа: Ubuntu 9.10
Дом: Debian testing/unstable и на всякий случай winxp в virtualbox.
Для разнообразия: моя домашняя страница -http://iportnov.ru
Спасибо сказали:
DSS
Сообщения: 390

Re: C++ и linux

Сообщение DSS »

DiIvPa писал(а):
14.01.2010 13:34
А в старом "дедовском" способе разве не так ? Читаем на http://alenacpp.blogspot.com/2005/08/c.html :
"Что делает приведение типов в стиле С: пытается использовать static_cast, если не получается, использует reinterpret_cast. Далее, если нужно, использует const_cast ."
т.е. получается то же самое ?

Не то же самое.
Конструкции *_cast указывают что делать явным образом. Приведение типов C-style может подложить свинку в виде неявного использования незатребованного функционала. Например, Вы хотите безопасно привести типы. И используете C-style. В этом случае можете словить небезопасное приведение из-за того, что C-style для несовместимых типов автоматически применит reinterpret_cast.
Спасибо сказали:
IMB
Сообщения: 2565
ОС: Debian

Re: C++ и linux

Сообщение IMB »

Имеется некий класс с фукцией Fifo_Handle getOutFifo() {return displayEnv.hOutFifo;} объявленной private.
В программе делаю следующее:

Код: Выделить всё

Display Display(args.format, args.width, args.height); //создаю объект
Video Video(Display::getInFifo(), Display::getOutFifo(),
                Capture::getInFifo(), Capture::getOutFifo(),
                args.width, args.height);

При компиляции ошибка:

Код: Выделить всё

Compiling main.o from main.cpp..
main.cpp: In function ‘int main(int, char**)’:
main.cpp:94: error: cannot call member function ‘Fifo_Object* Display::getInFifo()’ without object
main.cpp:94: error: cannot call member function ‘Fifo_Object* Display::getOutFifo()’ without object
main.cpp:95: error: cannot call member function ‘Fifo_Object* Capture::getInFifo()’ without object
main.cpp:95: error: cannot call member function ‘Fifo_Object* Capture::getOutFifo()’ without object
make: *** [main.o] Error 1

Я не понимаю почему говорится о отсутствии объекта когда я его создаю первой строчкой?
Спасибо.
Спасибо сказали:
Аватара пользователя
Portnov
Модератор
Сообщения: 1786
Статус: Матёрый линуксоид
ОС: Debian testing/unstable

Re: C++ и linux

Сообщение Portnov »

Вот вам про неочевидность синтаксиса С++ ;)
Display::getInFifo() - это обращение к методу класса Display. Обращение к методу объекта Display будет Display.getInFifo() (через точку). И, наверное, не надо класс и экземпляр называть одним именем - только путаницу создаёте.
Работа: Ubuntu 9.10
Дом: Debian testing/unstable и на всякий случай winxp в virtualbox.
Для разнообразия: моя домашняя страница -http://iportnov.ru
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C++ и linux

Сообщение eddy »

Не знаю, как опытные программисты, а я вот уже два дня с "граблями" разбирался, пока не нашел, наконец, свою ошибку. Итак, имеем: сишный CGI, который при получении начальных данных должен сделать fork. Родительский процесс сообщает, что все ОК и тихо умирает, дочерний продолжает работать в качестве демона, собирает информацию, а при следующих обращениях посредством сигналов дочерний процесс выдает информацию через FIFO.
Все вроде работало, но родительский процесс никак не хотел "по тихому" умирать: при тестировании в консоли все было отлично, а вот из браузера первое обращение вызывало подвисание xmlHttpRequest'а и страничку приходилось обновлять вручную. Что я только не делал, пока не вспомнил: пока в родительском процессе есть открытые дескрипторы файлов, наследуемые дочерним, он ни в какую не "умрет". Сделал так:

Код: Выделить всё

    fclose(stdin);
    fclose(stdout);
    fclose(stderr);
    if((pid = fork()) != 0){exit(0);}

и все стало нормально работать (сначала я только закрыл stdout, ломал-ломал голову, закрыл stdin, ломал еще, пока не вспомнил про stderr :))
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: C++ и linux

Сообщение watashiwa_daredeska »

eddy писал(а):
11.04.2010 02:52
пока в родительском процессе есть открытые дескрипторы файлов, наследуемые дочерним, он ни в какую не "умрет".
Бред сивой кобылы. Процесс нормально умирает, а вот веб-сервер определяет окончание обработки запроса и генерации ответа не по смерти CGI-скрипта, а по закрытию пайпов.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C++ и linux

Сообщение eddy »

watashiwa_darede... писал(а):
11.04.2010 13:09
Процесс нормально умирает, а вот веб-сервер определяет окончание обработки запроса и генерации ответа не по смерти CGI-скрипта, а по закрытию пайпов.

А почему же тогда скрипт не отдавал ответ даже после закрытия stdin и stdout, а только после закрытия всех трех дескрипторов?
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: C++ и linux

Сообщение watashiwa_daredeska »

Видимо, потому, что вебсервер ждёт закрытия всех трёх.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C++ и linux

Сообщение eddy »

watashiwa_darede... писал(а):
11.04.2010 17:00
Видимо, потому, что вебсервер ждёт закрытия всех трёх.

Понятно. Но для меня это была новость :)
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
gramozeka
Сообщения: 204
ОС: Slackware-14

Re: C++ и linux

Сообщение gramozeka »

zl3p писал(а):
20.09.2007 20:28

Код: Выделить всё

std::cout << "Hello, C++!" << std::endl;

имхо, длиннова-то будет. Я запутался, как же всё же писать. Мы это в школе не проходили. Где эти стандарты описаны вообще?


ищите и обрящете ...
... ну я же просил четыреста капель , а сдесь четыреста две ...
Спасибо сказали: