none
Unterschiedl. Ergebnisse bei Compiler MS VS .NET2003 und MS VS 2008 RRS feed

  • Frage

  • Hallo,

    ich habe unten angefügtes Programm eimal mit MS VS .NET2003  und  einmal mit MS VS 2008 compiliert und es kommen erstaunlicherweise unterschiedliche Ergebnisse heraus.
    Beim 2003er kommt das erwartete Ergebnis heraus, beim 2008er nicht.

    Es wird einmal von double direkt auf ein uchar gecastet, das andere mal erst auf ein uint und dann erst auf ein uchar.
    Kann mir jemand sagen, ob das plausibel erkärbar ist? Meiner Meinung nach dürften da keine Unterschiede sein.


    int main() {

        unsigned char x, data_ub;
        double        input_f64, output_f64;
       
        for (x=0; x<20; x++){
            input_f64 = (rand()/((double)RAND_MAX))*(1.296E9)+-6.48E8;

         data_ub  = ((unsigned char)((input_f64+6.48E8)/0.3017485143))&0xff;
         output_f64  = data_ub * 0.3017485143 -6.48E8;
         printf ("(Cast int8)  INP = %f   OUTP = %f  DATA = %d\n",   input_f64, output_f64, data_ub);

         data_ub = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)))&0xff;
         output_f64  = data_ub * 0.3017485143 -6.48E8;
         printf ("(Cast int32) INP = %f   OUTP = %f  DATA = %d\n\n", input_f64, output_f64, data_ub);
     }
    }

    Dienstag, 3. November 2009 10:21

Antworten

  • Was für einen Sinn soll denn eine Funktion ergeben, wo Du "rand" verwendest und dann auch noch immer das gleiche Ergebnis erwartest... und dann auch noch nicht man "srand" aufrufst (und somit initialisierst)....
    Dein Code hat, egal mit welchem Compiler übersetzt, einfach ein unbekanntes verhalten.
    Rufe "srand" auf, dann hat er ein "sinnvolles" Verhalten (wobei das Ergebnis immer sinnfrei bleibt, da es jedesmal anders ist... auch unabhängig vom Compiler).
    Jochen Kalmbach (MVP VC++)
    Dienstag, 3. November 2009 20:18

Alle Antworten

  • sind wahrscheinlich unterschiedliche compiler-versionen.
    ich kann da aber auch nicht weiterhelfen.
    Dienstag, 3. November 2009 14:57
  • Was für einen Sinn soll denn eine Funktion ergeben, wo Du "rand" verwendest und dann auch noch immer das gleiche Ergebnis erwartest... und dann auch noch nicht man "srand" aufrufst (und somit initialisierst)....
    Dein Code hat, egal mit welchem Compiler übersetzt, einfach ein unbekanntes verhalten.
    Rufe "srand" auf, dann hat er ein "sinnvolles" Verhalten (wobei das Ergebnis immer sinnfrei bleibt, da es jedesmal anders ist... auch unabhängig vom Compiler).
    Jochen Kalmbach (MVP VC++)
    Dienstag, 3. November 2009 20:18
  • Na gut.
    Um einen Sinn darin zu sehen etwas ausführlicher:

    Ich muß einen double-Wert auf den CAN-Bus bringen und dafür habe ich 4 Byte zur Verfügung.
    Um die ganze Sache zu prüfen, ob dabei auch wirklich das richtige passiert habe ich die Gegenrichtung programmiert und vergleiche dann input_f64 mit output_f64.
    Da ich die Tests mit VS2003 gemacht habe und mein Kollege dann mit VS2008 gearbeitet hat, habe ich meine Tests als i.O. abgehakt, bei meinem Kollegen hats gekracht bei data[0], da wir es mit einem direkten Cast auf UCHAR umgesetzt hatten.

    Hier nun ein denk ich sinnvolleres Programm, ergänzt um die anderen 3 Bytes:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>

    int main() {

        unsigned char x, data_ub[4];
        double        input_f64, output_f64;
       
        for (x=0; x<20; x++){
            input_f64 = (rand()/((double)RAND_MAX))*(1.296E9)+-6.48E8;

            data_ub[3] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)>>24))&0xff;
            data_ub[2] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)>>16))&0xff;
            data_ub[1] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)>>8))&0xff;
         data_ub[0] = ((unsigned char)((input_f64+6.48E8)/0.3017485143))&0xff;
         output_f64 = ((double)((unsigned int)(data_ub[3] & 0xff) << 24) + (double)((unsigned int)(data_ub[2] & 0xff) << 16) + (double)((unsigned int)(data_ub[1] & 0xff) << 8) + (double)((unsigned int)(data_ub[0] & 0xff) )) * (0.3017485143) + (-6.48E8);
         printf ("(Cast int8)  INP = %f   OUTP = %f  DATA[0] = %d\n",   input_f64, output_f64, data_ub[0]);

            data_ub[3] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)>>24))&0xff;
            data_ub[2] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)>>16))&0xff;
            data_ub[1] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)>>8))&0xff;
           data_ub[0] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)))&0xff;
         output_f64 = ((double)((unsigned int)(data_ub[3] & 0xff) << 24) + (double)((unsigned int)(data_ub[2] & 0xff) << 16) + (double)((unsigned int)(data_ub[1] & 0xff) << 8) + (double)((unsigned int)(data_ub[0] & 0xff) )) * (0.3017485143) + (-6.48E8);
         printf ("(Cast int32) INP = %f   OUTP = %f  DATA[0] = %d\n\n", input_f64, output_f64, data_ub[0]);
     }
    }


    Ergebnis mit VS2003:
    (Cast int8)  INP = -646378368.480483   OUTP = -646378368.481324  DATA3 = 164
    (Cast int32) INP = -646378368.480483   OUTP = -646378368.481324  DATA3 = 164
    (Cast int8)  INP = 82406567.583239   OUTP = 82406567.506312  DATA3 = 141
    (Cast int32) INP = 82406567.583239   OUTP = 82406567.506312  DATA3 = 141
    Ergebnis mit VS2008:
    (Cast int8)  INP = -646378368.480483   OUTP = -646378368.481324  DATA[0] = 164
    (Cast int32) INP = -646378368.480483   OUTP = -646378368.481324  DATA[0] = 164
    (Cast int8)  INP = 82406567.583239   OUTP = 82406524.959771  DATA[0] = 0
    (Cast int32) INP = 82406567.583239   OUTP = 82406567.506312  DATA[0] = 141


    Meiner Meinung nach müßten doch bei den beiden Codezeilen, egal mit welchem Compiler, dasselbe rauskommen:
         data_ub[0] = ((unsigned char)((input_f64+6.48E8)/0.3017485143))&0xff;
         data_ub[0] = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)))&0xff;

    Mittwoch, 4. November 2009 07:13
  • Also, wir reduzieren es zuerst einmal auf ein Minimal-Beispiel:
    #include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    int _tmain()
    {
      double input_f64 = 82406567.583239;
      unsigned char uc1 = ((unsigned char)((input_f64+6.48E8)/0.3017485143))&0xff;
      unsigned char uc2 = ((unsigned char)((unsigned int)((input_f64+6.48E8)/0.3017485143)))&0xff;
    
      printf("%d - %d", uc1, uc2);
    }
    Ist das so ok? Tritt hier der Fehler auf?
    Ich habe es mit VS2008 und VS2003 probiert. Beidesmal kommt 141 raus...

    Warum machst Du eh so komplizierte Rechnungen?
    Wandle den "double" in einen "float" um und verschiecke diese 4 bytes... es ist mir ein Rätsel wie man eine Zahl so kompliziert über den CAN-Bus schicken muss... mit "float" hätte man sich sogar noch an einen Standard gehalten (IEEE).


    Also, bitte stelle ein beispiel zur Verfügung, wo das Problem auftritt!
    Du verwendest hier definitiv zwei verschiedene Codes, da ich in dem von Dir geposteten Code auch keine printf-Ausgabe finden kann wo "DATA3" rauskommen könnte (was Du ja als vergleich aufführst).
    Jochen Kalmbach (MVP VC++)
    Mittwoch, 4. November 2009 07:26
  • Die komplizierten Berechnungen sind leider nicht auf meinem Mist gewachsen; das haben andere Köpfe definiert!
    Auch die Belegung der Daten auf dem CAN-Bus sind vorgeschrieben und bei uns werden alle Daten als Fixed-Point-Daten übertragen.
    Sorry für das DATA3; das hab ich noch schnell im printf geändert.
    Aber egal, das Beispiel ist gut und übersichtlich.

    hier mein kompletter Ausdruck in der DOS-Box:


    C:\work\kalmbach>setvars.bat vc7
    Setting environment for using Microsoft Visual Studio .NET 2003 tools.
    (If you have another version of Visual Studio or Visual C++ installed and wish
    to use its tools from the command line, run vcvars32.bat for that version.)

    C:\work\kalmbach>nmake clean

    Microsoft (R) Program Maintenance Utility Version 7.10.3077
    Copyright (C) Microsoft Corporation.  All rights reserved.

            del kalmbach.exe
            del kalmbach.obj

    C:\work\kalmbach>nmake

    Microsoft (R) Program Maintenance Utility Version 7.10.3077
    Copyright (C) Microsoft Corporation.  All rights reserved.

            cl /nologo -c .\kalmbach.c
    kalmbach.c
            link -nologo /DEBUG .\kalmbach.obj
    LINK : LNK6004: kalmbach.exe not found or not built by the last incremental link; performing full link

    C:\work\kalmbach>kalmbach.exe
    141 - 141
    C:\work\kalmbach>setvars.bat vc9ee
    Setting environment for using Microsoft Visual Studio 2008 x86 tools.

    C:\work\kalmbach>nmake clean

    Microsoft (R) Program Maintenance Utility, Version 9.00.30729.01
    Copyright (C) Microsoft Corporation.  All rights reserved.

            del kalmbach.exe
            del kalmbach.obj

    C:\work\kalmbach>nmake

    Microsoft (R) Program Maintenance Utility, Version 9.00.30729.01
    Copyright (C) Microsoft Corporation.  All rights reserved.

            cl /nologo -c .\kalmbach.c
    kalmbach.c
            link -nologo /DEBUG .\kalmbach.obj
    LINK : warning LNK4076: Inkrementelle Statusdatei "kalmbach.ilk" ungültig; Link erfolgt nicht inkrementell.

    C:\work\kalmbach>kalmbach.exe
    0 - 141
    C:\work\kalmbach>

    Mittwoch, 4. November 2009 07:52
  • WECLHES Beispiel ist gut und übersichtlich? Meines? Ja. Und da tritt der Fehler nicht auf.

    Poste bitte ein *einfaches* Beispiel (ohne rand), wo sich das Problem nachvollziehn lässt!
    Jochen Kalmbach (MVP VC++)
    Mittwoch, 4. November 2009 10:59
  • Der obige Audruck ist dein Beispiel-Programm und bei mir tritt der Fehler auf!
    0 - 141
    Mittwoch, 4. November 2009 11:05
  • Also, der Unterschied in VS2008 ist zwischen Release und Debug.
    Release kommt das raus, was Du denkst, in Debug kommt 0 raus.

    Was jetzt aber richtig ist, kann ich Dir leider nicht sagen, da ich den Code auseiander nehmen müsste un ich dazu aktuell keine Zeit habe... vielleicht findet sich ja jemand anders...
    Jochen Kalmbach (MVP VC++)
    Mittwoch, 4. November 2009 12:53
  • Alternativ kannst Du natürlich den MS Support kontaktieren, falls es sich um einen Copiler-Bug handelt (was fast den Anschein hat).
    Hast Du oder Ihr eine MSDN-Subscription? Dann habt Ihr sowieso i.d.R. 3-4 Support-Anfragen pro Jahr frei!
    Siehe:
    http://msdn.microsoft.com/de-de/library/2ew9zahx(VS.80).aspx
    Tel.: 01805/22 95 52 (Geschäftskunden)

    Alternativ kannst Du dazu auch einen Bug auf
    http://connect.microsoft.com/VisualStudio/
    melden!
    Jochen Kalmbach (MVP VC++)
    Mittwoch, 4. November 2009 16:30