[ Sini82 @ 28.08.2010. 18:34 ] @
Code:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    char c;
    c='č';
    cout<<"č="<<int(c);
    getchar();
    return 0;
}


$ g++ znak.cpp -o znak
znak.cpp:7:4: warning: multi-character character constant
znak.cpp: In function ‘int main()’:
znak.cpp:7: warning: overflow in implicit constant conversion
$ ./znak
č=-115
$


Može li promjenjiva znakovnog tipa (char) da uzima vrijednosti znakova ć, č, đ, š, š?
[ Mihajlo Cvetanović @ 28.08.2010. 18:46 ] @
Po standardu umesto char moraš da koristiš wchar_t da se informacija o slovu č ne bi izgubila. Tip wchar_t je na Linuxu 32-bitan, a na Widowsu je 16-bitan.
[ Sini82 @ 28.08.2010. 19:47 ] @
Zamijenio sam "char" sa "wchar_t" (i dalje mi javlja grešku):


$ g++ znak.cpp -o znak
znak.cpp:8:4: warning: multi-character character constant
$
[ Mihajlo Cvetanović @ 28.08.2010. 21:12 ] @
Zašto se promenila linija upozorenja sa 7 na 8?

Ne znam kako se to radi na gcc-u. Možda treba da staviš slovo L ispred navodnika, L'č', inače kompajler pokušava da interpretira č kao UTF-8, koji je dva bajta, koja ne mogu da stanu u jednostruke navodnike.
[ Sini82 @ 29.08.2010. 11:00 ] @
Hvala, uspjelo je!

Promijenila se linija upozorenja sa 7 na 8 jer sam dodao jedan red komentara ispred (obrisao sam taj red, privremeno mi je trebao).

Ovo sa L nisam nikada prije vidio.

1. Kako da napravim da radi

Code:
wchar_t c;
cin>>c;
?

2. Kako da radim sa ćčđšžž ako koristim stringove (pokušao sam sa wchar_t* c, javlja gresku)?
[ Mihajlo Cvetanović @ 29.08.2010. 11:30 ] @
Umesto cin i cout moraš da koristiš wcin i wcout. String literale koristiš isto kao i karakter literale, L"čćšđž". Ovo ja pretpostavljam da znam šta me pitaš, ali ne znam zasigurno jer nisi naveo kod koji pravi rešku, niti poruku greške.
[ Sini82 @ 29.08.2010. 12:13 ] @
Ne radi ni wcin ni wcout? Ne javlja pri kompilaciji gresku. Dešava se sledeće:

-kada u kodu koji sam već postavio u prvom postu zamijenim osmi red sa
Code:
cout<<c;
dobijam izlaz (vraća ako se ne varam int(c))
$ ./znak
269
$
;
Kada ga zamijenim sa
Code:
wcout<<c;
dobijam izlaz (vraća ?)
$ ./znak
?
$
;

-kada u istom kodu zamijenim i sedmi red sa
Code:
wcin>>c;
dobijam izlaz (ne daje izlaz, pitanje je da li se u promjenjivu c učitava znak "č")
$ ./znak
č
$
.

Kada ovo riješimo, onda ću da pokušam sa stringovima.
[ Mihajlo Cvetanović @ 29.08.2010. 12:29 ] @
Možda konzola treba da se podesi na Unicode nekako. To mora da ti pomogne neko ko se razume u Linux.
[ Sini82 @ 29.08.2010. 12:30 ] @
Konzola mi je podešena na Unicode (UTF-8).

Prvo da riješimo wchar_t, ovo neka ostane za kasnije.

Code:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    const wchar_t* s;
    s=L"ćčđšž";
    cout<<s;//wcout<<s;
    getchar();
    return 0;
}



$ ./znak
0x40093c
$


Kada zamijenim osmi red sa komentarom desno:

$ ./znak
?????
$


Code:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    wchar_t* s;
    wcin>>s;
    wcout<<s;
    getchar();
    return 0;
}


$ ./znak
ćčšđž
$


Drugi ulaz:

$ ./znak
kljui
Segmentation fault
$
[ Mihajlo Cvetanović @ 29.08.2010. 13:21 ] @
cin i wcin se ne mogu koristiti za pointere na karaktere, pa ni za stringove. Mogu da se koriste za osnovne tipove, char, int, float i slično, ali ne za char*. Možeš da koristiš std::string, ili std::wstring, ali samo ako učitavaš niz znakova bez razmaka. Ako hoćeš i razmak onda moraš ovako: getline(cin, s, '\n'), gde je s tipa string.

Kažeš da je konzola podešena na Unicode UTF-8. Probaj da je podesiš na Unicode UTF-32, jer to je wchar_t.
[ Goran Rakić @ 29.08.2010. 13:38 ] @
Uobičajeno je da se radi sa UTF-8. Tada učitavaš niz bajtova (primeti da je tip char logičnije tumačiti kao byte!) i isto tako ih ispisuješ. Ako želiš da prebrojiš, iteriraš, menjaš... vodiš računa o razlici broja karaktera i broja bajtova u saglasju sa UTF-8 kodiranjem. Ne možeš da očekuješ od korisnika tvog programa da menjaju kodnu stranu terminala.

E sada šta se dešava sa literalima u kodu. GCC literale koji su pokazivač na char predstavlja kao nisku u UTF-8 (ASCII je jedan bajt, ostalo je širine 2-4 bajta, otuda poruka o multibyte char constant), a široke literale (one sa L"...") kao UTF-16 ili UTF-32 zavisno od širine wchar. Drugi kompajler može da koristi drugu kodnu stranu i tako ograniči portabilnost koda.

Sa druge strane, ne možeš da pišeš po nealociranoj memoriji. Moraš da pripremiš prostor na koji pokazuje *s pre std::cin >> s, to su već sasvim početničke stvari.
[ Sini82 @ 29.08.2010. 13:39 ] @
Hvala, pokušavaću i dalje dok ne uspijem.
[ Goran Rakić @ 29.08.2010. 13:51 ] @
Bolje je prvo razumeti problem, nego pokušavati bezuspešno.
[ tkaranovic @ 29.08.2010. 17:32 ] @
Nije mi jasno što se pominje utf8 u vezi konzole?

Ili podešavanje konzole na unikod?

U win konzoli je oem cp ili api za unikod. wcin i wcout rade samo sa oem cp, a api omogućava
unikod. U nastavku su primeri za ovo što sam napisao. Ako neko ima primer za drugačiji rad win konzole, voleo bih da to vidim!

Primeri rade sa VS 2008 C++ i Embarcadero C++ Builderom.

Ovo:
Code:

#include <iostream>
#include <stdio.h>
#include <windows.h> 

using namespace std;
int main()
{
    int kcp;
    kcp = GetConsoleCP();
    wcout<<int(kcp)<<" <- oemcp konzole\n";

    char *c = "ź†Đ秬ŹŃć¦";
    cout<<c<<"\n";
    getchar();
    return 0;
}

Ispiše u konzoli:

852 <- oemcp konzole
čćđšžČĆĐŠŽ

A unikod može ovako (WriteConsoleW):
Code:

#define UNICODE

#include <windows.h>

int main()
{
    LPDWORD i = 0;
    wchar_t  *c = L"čćđšžČĆĐŠŽ";
    HANDLE h;
    h = GetStdHandle(STD_OUTPUT_HANDLE);
    WriteConsole(h, c, 10, i, NULL);
    return 0;
}

Ispiše: čćđšžČĆĐŠŽ.

Reimo, kodovi za slovo č:

oem cp 852 - 159
ansi cp 1250 - 232
unikod - 269
[ Mihajlo Cvetanović @ 29.08.2010. 17:41 ] @
Ako se ne varam ovde se priča o Linuxu a ne o Windowsu.
[ pera89 @ 29.08.2010. 18:48 ] @
cin i cout mogu da se koriste za pointere na karaktere. Koliko vidim greska sto je to sto nije alocirana memorija. Koristi pointer na char i u njega pokusava da smesti string za koji nije alocirao memoriju. Probaj ovako, nisam testirao:
Code:

int main(){
    wchar_t* s;
    s=new wchar_t[40];
    wcin>>s;
    wcout<<s;
    getchar();
    return 0;
}
[ tkaranovic @ 29.08.2010. 21:31 ] @
Citat:
mihajlo cvetanović
Ako se ne varam ovde se priča o Linuxu a ne o Windowsu.


To me i interesuje, napisao sam kako je u win (napisao sam win) konzoli.

Linux nema oem cp?

Ima nešto slično WriteConsole što ispsisuje utf8?

Naravno, pitam one koji rade u Linuxu pa to znaju.
[ Sini82 @ 30.08.2010. 13:07 ] @
Hvala tkaranovic i pera89. Isprobao sam vaše prijedloge, nisu dali rezultate.

Problem je riješen, nadam se da će nekome koristiti:

Code:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    char c[50];
    int i=1;
    int j=0;
    c[0]='a';
    while (c[i-1]!='!') 
        {
            cin>>c[i];
            i++;
        }
    for (j=1;j<i-1;j++)
        cout<<c[j];
    getchar();
    getchar();
    return 0;
}



$ ./znak
ćčđšž!
ćčđšž
$


ć=(xy), int(x)=-60, int(y)=-121, x=char(-60), y=char(-121);
č=(xy), int(x)=-60, int(y)=-115, x=char(-60), y=char(-115);
đ=(xy), int(x)=-60, int(y)=-111, x=char(-60), y=char(-111);
š=(xy), int(x)=-59, int(y)=-95, x=char(-59), y=char(-95);
ž=(xy), int(x)=-59, int(y)=-66, x=char(-59), y=char(-66).
[ Goran Rakić @ 30.08.2010. 13:26 ] @
Ovde učitavaš niz bajtova u UTF-8 kodiranju, ovi znaci se predstavljaju dvobajtno, a dužina za druge ide od 1 do četiri. Kada pročitaš prvi bajt (char) imaš informaciju u vodećim bitovima o dužini koda i znaš koliko još bajtova treba da pročitaš za celo slovo. Pogledaj stranicu na Vikipediji: http://en.wikipedia.org/wiki/UTF-8#Description

Kada ispisuješ dovoljno je da baciš u terminal tu sekvencu bajtova i znak će biti ispravno prikazan. Prikaz znaka je posao koji radi terminal.

Ako ne želiš da pišeš sve od nule možeš da koristiš gotove biblioteke, na primer glibmm koji ima Glib::ustring klasu.

Kodnu stranicu terminala možeš da proveriš sa setlocale/nl_langinfo(CODESET) ili čitajući LC_ALL/LC_CTYPE/LANG promenljive okruženja koje kodnu stranicu navode iza tačke. Onda možeš da koristiš iconv biblitoeku da pretvoriš svoj izlaz/ulaz iz internog UTF-8 u kodnu stranu terminala. Ipak, verujem da sasvim bezbrižno možeš da pretpostaviš da terminal koristi UTF-8.

Učitavanje u wchar_t ne radi zato što pretpostavlja da je tvoj ulaz UTF-16/UTF-32 zavisno od širine. Dakle ili podesiš terminal da to bude kodna stranica ili pročitaš iz UTF-8 u niz bajtova pa konvertuješ. Za konverziju možeš da koristiš mbsrtowcs() i wcsrtombs() i onda upotrebljavaš standardne "široke" funkcije iz glibc-a. Ove funkcije za konverziju same prepoznaju kodnu stranu terminala.

Da bi std::wcout/std::wcin prepoznali kodnu stranu terminala, ako njih želiš da koristiš, potrebno je odraditi setlocale() poziv:
Code (c):

#include <iostream>
int main() {
    wchar_t* s;
    s=new wchar_t[40];
    std::setlocale(LC_ALL, "");
    std::wcin >> s;
    std::wcout << s << std::endl;
    return 0;
}
 



[Ovu poruku je menjao Goran Rakić dana 30.08.2010. u 15:03 GMT+1]
[ Sini82 @ 30.08.2010. 13:42 ] @
Hvala ti na savjetima i pojašnjenju.
[ tkaranovic @ 30.08.2010. 17:14 ] @
Može li još samo za nas win "posmatrače" šta ispiše:

Code:

#include <iostream>
using namespace std;
int main() {
    printf( "setlocale:\n%s\n", setlocale(LC_ALL, "") );
    return 0;
}


u win ispiše ...852
[ Sini82 @ 30.08.2010. 18:46 ] @
Code:
//win.cpp
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
    printf( "setlocale:\n%s\n", setlocale(LC_ALL, "") );
    return 0;
}


$g++ win.cpp -o win
$ ./win
setlocale:
en_US.utf8
$

[ Sini82 @ 30.08.2010. 22:26 ] @
Svaka cast Gorane. Uspjelo je, sada rade wcin i wcout.