Problem jest taki :
Potrzebuje po wpisaniu liczby zmiennoprzecinkowej podczas programu dostać jej wartość w systemie binarnym;
Czy jest możliwe dostanie sie do pamięci w ktorej zarezerwowane jest miejsce dla zmiennej i odczytanie jej ? Bo podobno
dane zapisywane tam są w systemie binarnym.
Czy wykonanie takich króków jest możliwe ? :
1.wczytanie zmiennej,
2.odczytanie adresu pamieci zmiennej poprzez $a,
3.dostanie sie pod adres zmiennej,
4.odczytanie bajt po bajcie zmiennej i wpisywanie do innej zmiennej,(16 bitów ? ),
5.wyswietlenie tej zmiennej.
Prosze o wyrozumiałość mogłem niedokładnie opisać swój problem lub źle podejść do wyciagania tych danych.
Z góry dziękuje za pomoc. Pozdrawiam
I nie prosze o kod tylko o wskazanie drogi bo mogłem źle zrozumieć cały proces deklarowania zmiennych i zapisywania ich w pamieci .
Tak, da się to wszystko zrobić. Najłatwiej to chyba zrobić unią które C wspiera z tego co się orientuję.
Np. tutaj masz jak to się robi:
http://msdn.microsoft.com/en-us/library/5dxy4b7b(v=vs.80).aspx
Jeżeli chodzi o ręczne kopiowanie, to też się da za pomocą operatora wyłuskania i memcpy
Trochę przerobisz i będzie ok.
#include <iostream>
void printBinary(const unsigned char val){
for(int i=7;i>=0;i--){
if(val &(1<<i))
std::cout<<"1";
else
std::cout<<"0";
}
}
int main(){
int n=100;
printBinary(n);
return 0;
};
Zmienna zmiennoprzecinkowa to po prostu zbiór bitów. Nie musisz nic konwertować. Aby dostać się do konkretnych bitów / bajtów wystarczy rzutowanie na typ całkowity:
#include <iostream>
using namespace std;
typedef unsigned long long ull; // 64-bit, sorry, nie wiem jak jest w C
void PrintBits(ull value, unsigned start, unsigned count)
{
ull mask = 1ULL << start;
while (count-- > 0) {
cout << ((value & mask) != 0) ? '1' : '0';
mask >>= 1;
}
}
int main()
{
double var;
while (cout << "Podaj wartosc zmiennej: ", cin >> var) {
ull *bits = (ull*)&var; // <----------- RZUTOWANIE
cout << "znak cecha mantysa" << endl;
PrintBits(*bits, 63, 1);
cout << " ";
PrintBits(*bits, 62, 11);
cout << " ";
PrintBits(*bits, 51, 52);
cout << endl;
}
}
Generalnie zasada jest taka, że najpierw rzutujesz na tym całkowity (jeśli typ wyjściowy nie jest takowym), a później przy pomocy operacji bitowych (>>, <<, &, ...) dostajesz się do konkretnych bitów/bajtów. Aby uniknąć pułapek z data alignment, typ całkowity na który rzutujesz musi być nie większy (w sensie sizeof) niż typ wyjściowy.
Przy takich rzeczach trzeba uważać na pułapki związane z data alignment/padding oraz endianem.
Witam,
Program wygląda tak :
//binarnie
#include <stdio.h>
void main(int argc,char *argv[])
{
//liczenie dla liczby dziesietnej
int i;
int rozmiar=8*sizeof(float);
char * n[rozmiar+1];
float a=6.23;
printf("Nazwa programu %s\n",argv[0]);
for(i=rozmiar;i>=0;i--){
if (((int)a & 1)==1) n[i]="1";
else n[i]="0";
a=(int)a>>1;
}
for(i=0;i<=rozmiar;i++){
if (i==0) printf("%s-",n[i]);
else if (i==8) printf("%s.",n[i]);
else printf(n[i]);
}
// koniec 1 programu
getchar();
}
a wynik jak w załączniku . Wzorowałem sie na rysunku //upload.wikimedia.org/wikipedia/commons/2/2e/IEEE-754-single1.svg
Jaki błąd popełniłem ??
Wiele. Po pierwsze, popraw wcięcia, bo trudno śledzić twoje pętle.
Po drugie, zapis (int)a
po prostu obcina ci część ułamkową, zostawiając całkowitą.
Żeby dostać się do bitów floata, użyj unii.
a teraz ?
<code class="c">
// binarnie
#include <stdio.h>
void main(int argc,char *argv[]){
float a;
int i;
int rozmiar=8*sizeof(int); //rozmiar int 4 bajty 1 bajt 8 bitow
char *n[rozmiar];
int maska=1; // binarnie 00000001
// wczytanie zmiennej float
printf("Podaj liczbe zmienno przecinkowa:");
scanf("%f",&a);
// rzutowanie a na long by móc robic operacje bitowe;
long b = *(long *)(&a);
for (i=rozmiar-1;i>=0;i--,b>>=1) {//przesuwa b o jedno miejsce prawo by porownac nastepny bit
if ((b & maska)==maska) n[i]="1";//porownuje bit z ostatnim maski bo 1 to 00000001
else n[i]="0";
}
printf("znak cecha mantysa \n"); // w 32 bitach 1 to znak kolejne 8 cecha nastepne to mantysa
for(i=0;i<rozmiar;i++)
{
if (i==0) printf(" %s ",n[i]);//jesli znak 1 to ujemne jesli 0 dodatnie
else if (i==1) printf(" %s",n[i]);//ułamek
else if (i==8) printf("%s ",n[i]);//ulamek
else printf(n[i]);//wykladnik
}
getchar();
getchar();
}
Teraz jest ok. Można jeszcze dopieścić parę rzeczy. Jak long
to long
a nie raz int
a raz long
. Zamiast tablicy łańcuchów (n
) użyć tablicy pojedynczych znaków. Ze stałych zrobić define'y.
I jeszcze taka rada - jeśli chodzi nam o bity (np. maski bitowe) to dobrą konwencją jest używać zapisu szesnastkowego liczb. Np. u ciebie maska to 1 - warto ją zapisać w postaci 0x00000001. Taki zapis sugeruje właśnie, że chodzi o liczbę, w której ustawione są konkretne bity.
#include <stdio.h>
#define ROZMIAR (8 * sizeof(long))
// binarnie 00000001
#define MASKA 0x00000001
void main(int argc,char *argv[])
{
float a;
int i;
char n[ROZMIAR];
// wczytanie zmiennej float
printf("Podaj liczbe zmienno przecinkowa:");
scanf("%f", &a);
// rzutowanie a na long by móc robic operacje bitowe;
long b = *(long *)(&a);
for (i = ROZMIAR - 1; i >= 0; i--, b >>= 1) { //przesuwa b o jedno miejsce prawo by porownac nastepny bit
n[i] = ((b & MASKA) != 0) ? '1' : '0'; //porownuje bit z ostatnim maski bo 1 to 00000001
}
printf("znak cecha mantysa \n"); // w 32 bitach 1 to znak kolejne 8 cecha nastepne to mantysa
printf("%.1s %.8s %.23s", n + 0, n + 1, n + 9);
getchar();
getchar();
}
float a;
long b = *(long *)(&a);
To jest, ściśle rzecz biorąc, undefined behavior w C99 (dozwolone jest w C++).
Dlaczego — szukaj: strict aliasing.
Przy włączonej optymalizacji kompilator C ma prawo zdetonować twój program na takim kodzie.
Ale to dopiero przy użyciu restricted
, czyż nie?
Bezpiecznie można rzutować na char * w C, w tym wypadku (i o ile dobrze pamiętam tylko dla char *) strict aliasing nie ma znaczenia.
mógłby mi ktos wytlumaczyc dzialanie tego kodu ?:
n[i] = ((b & MASKA) != 0) ? '1' : '0';
to cos w stylu if else ?
n[i] = ((b & MASKA) != 0) ? '1' : '0';
if((b & MASKA) != 0) {
n[i] = 1;
} else {
n[i] = 0;
}
czyli zamiast int b=(int)&a wystarczy zrobic tak ?
#include <stdio.h>
union{
float f;
int i;
}u;
void main(void){
printf("Podaj liczbe zmienno przecinkowa:");
scanf("%f",&u.f);
b=u.i;
}
tak ?
Tak, tylko zadeklaruj b, bo tego nie zrobiłeś
no tak tak :)