2017-02-03 3 views
-6

Mein Projekt ist das Scannen eines Adressraums (in meinem Fall 0x00000000 - 0xffffffff oder 0 - (2) -1) für ein Muster und Rückgabe in einem Array die Orte im Speicher, an denen das Muster gefunden wurde (könnte mehrfach vorkommen).Fehler beim Versuch, double to char zu simulieren *

Da der Adressraum 32 Bits ist, ist ich ein Doppel und max ist pow (2,32) (auch ein Doppel).

Ich möchte den ursprünglichen Wert von intac int behalten, damit ich das verwenden kann, um den Standort zu melden, wo das Muster gefunden wurde (da das Finden des Musters tatsächlich mehrere Bytes nach i vorwärts benötigt), also möchte ich temp, deklariert als char *, um den Wert von i zu kopieren. Dann, später in meinem Programm, werde ich die Temperatur dereferenzieren.

Das Problem, in das ich hineingeraten bin, ist ein Double kann nicht als char * umgewandelt werden. Ein Int kann sein; Da der Adressraum jedoch 32 Bit (nicht 16) beträgt, brauche ich ein Double, das genau groß genug ist, um 2^32 darzustellen.

Kann ich irgendetwas dagegen tun?

+1

Kannst du 'uint32_t' stattdessen verwenden? –

+0

Sie können ein 'long' oder sogar ein' long long' verwenden. – DyZ

+3

Außerdem erhalten Sie fast sofort eine Zugriffsverletzung (aka "segfault"), da nicht alle Speicheradressen zugänglich sind. ;) –

Antwort

4

In C sind double und float nicht so dargestellt, wie Sie denken, sie sind; Dieser Code zeigt, dass:

#include <stdio.h> 

typedef union _DI 
{ 
    double d; 
    int i; 
} DI; 

int main() 
{ 
    DI di; 
    di.d = 3.00; 
    printf("%d\n", di.i); 
    return 0; 
} 

Sie werden nicht eine Leistung von 3 in diesem Fall sehen.

Im Allgemeinen, auch wenn Sie den Speicher anderer Prozesse lesen könnten, wird Ihre Strategie auf keinem modernen Betriebssystem funktionieren, weil der virtuelle Speicher (der Adressraum, den ein Prozess "sieht") nicht unbedingt (tatsächlich) Normalerweise repräsentiert es nicht den physischen Speicher auf dem System).

2

Ahh, eine Schulaufgabe. OK dann.

uint32_t i; 
for (i = 0; i < 0xFFFFFFFF; i++) 
{ 
    char *x = (char *)i; 
    // Do magic here. 
} 

// Also, the above code skips on 0xFFFFFFFF itself, so magic that one address here. 
// But if your pattern is longer than 1 byte, then it's not necessary 
// (in fact, use something less than 0xFFFFFFFF in the above loop then) 
+0

Mein Compiler (gcc) mag den Typ uint32_t nicht: Fehler: unbekannter Typname 'uint32_t' Ich vergesse, eine Bibliothek zu importieren? –

+2

@clueless_c_programmer Sie benötigen '#include ', um 'uint32_t' zu verwenden. – zwol

+0

Ich habe versucht, genau das umzusetzen, was Sie oben haben - die Schleife endet nie. Die Zahlen gehen bis zu 0xfffffffe und dann geht es wieder von 0 zurück. –

3

Verwenden Sie niemals eine Gleitkommavariable, um eine ganze Zahl zu speichern. Gleitkommavariablen führen ungefähre Berechnungen durch. Es würde in diesem Fall funktionieren, weil die Integer klein genug sind, aber um das zu wissen, braucht man intime Kenntnisse darüber, wie Gleitkommazahlen auf einer bestimmten Maschine/einem Compiler funktionieren und welcher Bereich von Ganzzahlen du verwendest. Außerdem ist es schwieriger, das Programm zu schreiben, und das Programm wäre langsamer.

C definiert einen Integer-Typ, der groß genug ist, um einen Zeiger zu speichern: uintptr_t. Sie können einen Zeiger auf uintptr_t und zurück werfen. Auf einem 32-Bit-Rechner ist.ein 32-Bit-Typ, so dass nur Werte von bis zu 2 -1 gespeichert werden können. Um eine Schleife auszudrücken, die den gesamten Bereich des Typs einschließlich des ersten und des letzten Werts abdeckt, können Sie keine gewöhnliche for-Schleife mit einer inkrementierten Variable verwenden, da die Endbedingung einen Wert des Schleifenindex erfordert, der außerhalb des Bereichs liegt. Wenn Sie naiv

schreiben
uintptr_t i; 
for (i = 0; i <= UINTPTR_MAX; i++) { 
    unsigned char *temp = (unsigned char *)i; 
    // ... 
} 

dann erhalten Sie eine Endlosschleife, weil nach der Iteration mit i gleich UINTPTR_MAX, laufen i++ wickelt den Wert von i auf 0. Die Tatsache, dass die Schleife auch unendlich gesehen werden kann, in ein einfacherer logischer Weg: Die Bedingung i <= UINTPTR_MAX ist immer wahr, da alle Werte des Typs kleiner oder gleich dem Maximum sind.

Sie können dies beheben, indem Sie den Test nahe am Ende der Schleife platzieren, bevor Sie die Variable inkrementieren.

i = 0; 
do { 
    unsigned char *temp = (unsigned char *)i; 
    // ... 
    if (i == UINTPTR_MAX) break; 
    i++; 
} while (1); 

Beachten Sie, dass die Erforschung von 4GB auf diese Weise extrem langsam sein wird, wenn Sie es sogar tun können. Sie erhalten einen Segmentierungsfehler, wenn Sie versuchen, auf eine Adresse zuzugreifen, die nicht zugeordnet ist. Sie können den segfault mit einem Signal-Handler behandeln, aber das ist schwierig und langsam. Was du versuchst, mag vielleicht nicht das sein, was dein Lehrer erwartet, aber es macht keinen praktischen Sinn.

Um den Speicher eines Prozesses unter Linux zu untersuchen, lesen Sie /proc/self/maps, um seine Speicherzuordnungen zu ermitteln. Ein Beispielcode in Python finden Sie in my answer on Unix.SE.

Beachten Sie auch, dass wenn Sie nach einem Muster suchen, Sie die Länge des gesamten Musters berücksichtigen müssen, eine Byte-für-Byte-Suche nicht die ganze Arbeit erledigt.

+0

Man könnte auch 'sysconf (_SC_PAGESIZE)' Bytes jedes Mal überspringen, wenn der Signal-Handler ausgelöst wird. Es wäre immer noch langsamer (wahrscheinlich viel langsamer) als die Analyse von '/ proc/self/maps', aber es würde vermeiden, '/ proc/self/maps' zu analysieren ;-) – zwol

2

Die Umwandlung eines double in einen Zeiger ist eine Constraint-Verletzung - daher der Fehler.

A floating type shall not be converted to any pointer type. C11dr §6.5.4 4


den gesamten 32-Bit-Adressraum zu scannen, verwenden eine do Schleife mit einer Lage Typ integer der [0 ... 0xFFFFFFFF] Bereich.

uint32_t address = 0; 
do { 
    char *p = (char *) address; 
    foo(p); 
} while (address++ < 0xFFFFFFFF); 
+0

Gleiches Problem wie einer der anderen Vorschläge - der Schleife endet nie. Ich drucke die Zahlen aus, um sicher zu gehen, und sie gehen den ganzen Weg bis zu 0xffffffff, bevor sie wieder von vorne anfangen. –

+0

@clueless_c_programmer Die Antwort _does not_ "wieder von vorne anfangen". Vielleicht hast du es falsch geschrieben oder verändert? – chux

Verwandte Themen