Variablen im Switch Statement



  • Salutos miteinander,

    ich habe ein kleines Problem mit einem Fehler welcher in einem Switch Statement auftaucht. Ich kann meinen Fehler nicht erkennen, welchen ich begangen habe und meine Problem Lösungsansätze haben mich ein wenig verwundert.

    Nachfolgender Abschnitt ist betroffen (Zeile 27-40):

    #include <stdlib.h>
    #include <stdbool.h>
    #include <string.h>
    /* Lua Includes */
    #include "lua/lua.h"
    #include "lua/lauxlib.h"
    #include "lua/lualib.h"
    
    int conf_get_value( lua_State *L, const char *key_name, char *buffer, \
                        unsigned int buffer_size )
    {
      if( !L || !key_name || buffer_size < 1 ){ return -1; }
      int return_value = 1;
      //printf( "Looking for key: %s\n", key_name );
      int type = lua_getglobal( L, key_name );
      switch( type )
      {
        case LUA_TNIL:
          //printf( "Got a Nil Data\n" );
          return_value = 0;
          break;
        case LUA_TBOOLEAN:
          //printf( "Got a Boolean Value\n" );
          //printf( "Name: %s Value: %i\n", lua_typename( L, type ), (bool)lua_toboolean( L, -1 ) );
          *((bool *)buffer) = (bool)lua_toboolean( L, -1 );
          break;
        case LUA_TSTRING:
          //printf( "Got a String Value\n" );
          //printf( "Name: %s Value: %s\n", lua_typename( L, type ), (char *)lua_tostring( L, -1 ) );
          size_t length = 0;
          char *tmp_r = (void*)0;
          tmp_r = (char *)lua_tolstring( L, -1, &length );
          if( length > buffer_size )
          {
            //printf( "Could not assign Value to buffer due to size\n" );
            return_value = -1;
            break;
          }
          memcpy( buffer, tmp_r, length );
          break;
        case LUA_TNUMBER:
          //printf( "Got a Number Value\n" );
          //printf( "Name: %s Value: %i\n", lua_typename( L, type ), (int)lua_tonumber( L, -1 ) );
          if( buffer_size == 1 )
          {
            *((char *)buffer) = (char)lua_tonumber( L, -1 );
          }
          else if( buffer_size == 8 )
          {
            *((int *)buffer) = (int)lua_tonumber( L, -1 );
          }
          else
          {
            return_value = -2;
          }
          break;
        case LUA_TTABLE:
          //printf( "Got a Table Value\n" );
          /* Test Angelegenheit */
          lua_pushnil( L );
          while( lua_next( L, -2 ) != 0 )
          {
            //printf( "K:%s - V:%s\n", luaL_typename( L, -2 ), luaL_typename( L, -1 ) );
            //printf( "K:%s - V:%i\n", (char *)lua_tostring( L, -2 ), (int)lua_tonumber( L, -1 ) );
            lua_pop( L, 1 );
          }
          break;
        default:
          //printf( "Got other data\n" );
          return_value = -3;
          break;
      }
      lua_pop( L, -1 );
      return return_value;
    }
    

    Mit den auskommentierten Print Anweisungen erhalte ich folgenden Fehler:

    make lua_test
    gcc -Wall -lm -o luatest luatest.c configuration.c ./objects/lfunc.o ./objects/lstring.o ./objects/lvm.o ./objects/ltablib.o ./objects/lcorolib.o ./objects/ltm.o ./objects/linit.o ./objects/ldo.o ./objects/lparser.o ./objects/lstrlib.o ./objects/ldblib.o ./objects/lbitlib.o ./objects/liolib.o ./objects/ltable.o ./objects/lmem.o ./objects/lbaselib.o ./objects/lutf8lib.o ./objects/lundump.o ./objects/lapi.o ./objects/lgc.o ./objects/loslib.o ./objects/lcode.o ./objects/lopcodes.o ./objects/llex.o ./objects/loadlib.o ./objects/lmathlib.o ./objects/lobject.o ./objects/lctype.o ./objects/lstate.o ./objects/lzio.o ./objects/ldump.o ./objects/lauxlib.o ./objects/ldebug.o
    luatest.c: In Funktion »main«:
    luatest.c:61:7: Warnung: Variable »ret_val« gesetzt, aber nicht verwendet [-Wunused-but-set-variable]
       int ret_val = conf_get_value( gd.config.Lconfig, "muh", \
           ^~~~~~~
    configuration.c: In Funktion »conf_get_value«:
    configuration.c:85:7: Fehler: eine Marke kann nur Teil einer Anweisung sein, und eine Deklaration ist keine Anweisung
           size_t length = 0;
           ^~~~~~
    configuration.c:86:7: Fehler: expected expression before »char«
           char *tmp_r = (void*)0;
           ^~~~
    configuration.c:87:7: Fehler: »tmp_r« nicht deklariert (erste Verwendung in dieser Funktion)
           tmp_r = (char *)lua_tolstring( L, -1, &length );
           ^~~~~
    configuration.c:87:7: Anmerkung: jeder nicht deklarierte Bezeichner wird nur einmal für jede Funktion, in der er vorkommt, gemeldet
    make: *** [Makefile:8: lua_test] Fehler 1
    

    Was mir zu denken gibt ist die Tatsache, dass ich diesen Fehler nicht erhalten, wenn ich eine der auskommentierten Print Anweisungen eine Zeile zuvor wieder ... nicht auskommentiere (?).

    Auch wenn ich den betroffenen Bereich in einen Block schiebe erhalte ich den Fehler nicht, also beispielsweise:

    case LUA_TSTRING:
          {
          //printf( "Got a String Value\n" );
          //printf( "Name: %s Value: %s\n", lua_typename( L, type ), (char *)lua_tostring( L, -1 ) );
          size_t length = 0;
          char *tmp_r = (void*)0;
          tmp_r = (char *)lua_tolstring( L, -1, &length );
          if( length > buffer_size )
          {
            //printf( "Could not assign Value to buffer due to size\n" );
            return_value = -2;
            break;
          }
          memcpy( buffer, tmp_r, length );
          break;
          }
    

    Aber diese Lösung halte ich für unsinnig, da eindeutig etwas mit dem Code nicht stimmt, aber ich begreife nicht, was.

    Habe die vorher gehenden Klammen sowie Semicolons geprüft und das Projekt nach Variablen mit dem Namen 'length' durchsucht, aber beides ist es nicht.

    Gemäß https://en.cppreference.com/w/c/language/switch ist als Statement alles gültig, sofern ich das richtig erfasst habe.

    switch ( expression ) statement		
    expression	-	any expression of integer type (char, signed or unsigned integer, or enumeration)
    statement	-	any statement (typically a compound statement). case: and default: labels are permitted in statement, and break; statement has special meaning.
    

    Ich weiß nicht, ob das noch Anwendung findet, aber in einem alten Beitrag hier aus dem Forum wurde angegeben, dass Variablendeklarationen nicht im Switch Block enthalten sein dürfen (https://www.c-plusplus.net/forum/topic/339412/brauche-hilfe-bei-menu).

    In diesem Zusammenhang wundert mich das Verhalten umso mehr, dass ich keinen Fehler erhalten sobald ich die Print Anweisungen setze.

    Könnt Ihr mir mitteilen, wo mein Fehler hier liegt?

    Danke im Voraus!



  • hast du denn mal versucht, die deklarationen nach oben zu setzen?



  • Die Zeilennummern der Fehlermeldungen passen nicht zum Code.



  • @Wade1234 sagte in Variablen im Switch Statement:

    hast du denn mal versucht, die deklarationen nach oben zu setzen?

    Falls du meinst, ich solle die Variablen außerhalb des Switch Blocks setzen, das scheint zu funktionieren. Es wurmt mich nur, da die Variablen dort auftauchen wo diese noch nicht benötigt werden. Daher ist das Problem mit der Nutzung des Codes theoretisch aus der Welt, GCC moniert zumindest nichts mehr zu meinem Code.

    Eine Erklärung für das Verhalten mit den Print Anweisungen hast du nicht zufällig? ^^

    @manni66 sagte in Variablen im Switch Statement:

    Die Zeilennummern der Fehlermeldungen passen nicht zum Code.

    Das ist korrekt. Davor befindet sich nur Code um die Lua Konfigurations Datei zu lesen. Daher habe ich es auf ein minimales Beispiel reduziert. Ist das in diesem Fall relevant? Dann reiche ich diese nach.



  • Das ist kein minimales Beispiel sondern ein Codeausschnitt. Nein, wir wollen keine hunderte von Zeilen sehen.

    Siehe
    https://www.c-plusplus.net/forum/topic/200753/du-brauchst-hilfe



  • @fairiestoy Das hat schon seinen Grund in der allgemeinen Lesbarkeit der Source und sei versichert, der Compiler erzeugt keinen Opcode für Sachen, die er nicht braucht.
    Die Erleichterungen nach C89 haben auch Verunsicherungen erzeugt.
    Und es würde mich wundern, wenn es mit den printfs() wirklich durchliefe.



  • @manni66 sagte in Variablen im Switch Statement:

    Das ist kein minimales Beispiel sondern ein Codeausschnitt. Nein, wir wollen keine hunderte von Zeilen sehen.

    Siehe
    https://www.c-plusplus.net/forum/topic/200753/du-brauchst-hilfe

    Zur Kenntnis genommen, danke dir für den Hinweis 👍

    @Sarkast sagte in Variablen im Switch Statement:

    @fairiestoy Das hat schon seinen Grund in der allgemeinen Lesbarkeit der Source und sei versichert, der Compiler erzeugt keinen Opcode für Sachen, die er nicht braucht.
    Die Erleichterungen nach C89 haben auch Verunsicherungen erzeugt.
    Und es würde mich wundern, wenn es mit den printfs() wirklich durchliefe.

    Zu deinem letzten Punkt und Mannis vorher gehenden Post, habe ich es einfach noch einmal mehrfach getestet mit wesentlich einfacherem Code:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int switch_test( int logic )
    {
      switch( logic )
      {
        case 1:
          printf( "Reached One\n" );
          break;
        case 2:
          printf( "Test zu Compiler Verhalten\n" );
          int test = 0;
          test = logic;
          printf( "Reached Two with val: %i\n", test );
          break;
        case 3:
          printf( "Reached Three\n" );
          break;
      }
      return logic;
    }
    
    int main( int argc, char *argv[argc] )
    {
      switch_test( 2 );
      return 0;
    }
    

    Dieser Code wird mit -Wall Schalter kompiliert ohne Probleme und ausgeführt. Kommentiere ich die Print Anweisung in Zeile 13 heraus, erhalte ich wieder denselben Fehler.

    Mich würde einfach interessieren, wieso dem so ist.

    OS: Manjaro 18.0.4
    Compiler: GCC 8.3.0

    Für die Hilfe, das offensichtlichste zu unternehmen, nämlich die Variablendeklaration einfach vor den Switch Block zu werfen, bedanke ich mich!



  • @fairiestoy sagte in Variablen im Switch Statement:

    @manni66 sagte in Variablen im Switch Statement:

    Das ist kein minimales Beispiel sondern ein Codeausschnitt. Nein, wir wollen keine hunderte von Zeilen sehen.

    Siehe
    https://www.c-plusplus.net/forum/topic/200753/du-brauchst-hilfe

    Zur Kenntnis genommen, danke dir für den Hinweis 👍

    @Sarkast sagte in Variablen im Switch Statement:

    @fairiestoy Das hat schon seinen Grund in der allgemeinen Lesbarkeit der Source und sei versichert, der Compiler erzeugt keinen Opcode für Sachen, die er nicht braucht.
    Die Erleichterungen nach C89 haben auch Verunsicherungen erzeugt.
    Und es würde mich wundern, wenn es mit den printfs() wirklich durchliefe.

    Zu deinem letzten Punkt und Mannis vorher gehenden Post, habe ich es einfach noch einmal mehrfach getestet mit wesentlich einfacherem Code:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int switch_test( int logic )
    {
      switch( logic )
      {
        case 1:
          printf( "Reached One\n" );
          break;
        case 2:
          printf( "Test zu Compiler Verhalten\n" );
          int test = 0;
          test = logic;
          printf( "Reached Two with val: %i\n", test );
          break;
        case 3:
          printf( "Reached Three\n" );
          break;
      }
      return logic;
    }
    
    int main( int argc, char *argv[argc] )
    {
      switch_test( 2 );
      return 0;
    }
    

    Dieser Code wird mit -Wall Schalter kompiliert ohne Probleme und ausgeführt. Kommentiere ich die Print Anweisung in Zeile 13 heraus, erhalte ich wieder denselben Fehler.

    Mich würde einfach interessieren, wieso dem so ist.

    OS: Manjaro 18.0.4
    Compiler: GCC 8.3.0

    Für die Hilfe, das offensichtlichste zu unternehmen, nämlich die Variablendeklaration einfach vor den Switch Block zu werfen, bedanke ich mich!

    Ich weiß, für den Konservativismus ziehe ich mir keine Liebe zu, offensichtlich ist das Verhalten des GCC nicht wirklich erklärbar. Allerdings bin ich über die Lockerungen durch C99 ff nicht wirklich informiert noch brauche ich sie und mag sie nicht, weil sie die Lesbarkeit der Source eher beeinträchtigen.
    Einfach an die alte IBM- Weisheit halten: "If it hurts, don't do it!" 😉



  • @fairiestoy sagte in Variablen im Switch Statement:

    configuration.c:85:7: Fehler: eine Marke kann nur Teil einer Anweisung sein, und eine Deklaration ist keine Anweisung
    size_t length = 0;
    ^~~~~~

    Das heisst: Ein Label, wie das von "case X:" erzeugte, muss bei einer Anweisung mit dran stehen. Das ist halt so ne C Regel, ob die jetzt Sinn macht oder nicht. Eine Deklaration ist keine Anweisung, also bekommst du nen Fehler. Wenn du vor der Deklaration das printf() hinschreibst bekommst du keinen Fehler mehr, da ein Funktionsaufruf eine Anweisung ist und damit die Regel erfüllt.

    Auch wenn ich den betroffenen Bereich in einen Block schiebe erhalte ich den Fehler nicht, also beispielsweise:

    Das wäre genau das was ich vorschlagen würde.



  • @fairiestoy sagte in Variablen im Switch Statement:

    Dieser Code wird mit -Wall Schalter kompiliert ohne Probleme und ausgeführt. Kommentiere ich die Print Anweisung in Zeile 13 heraus, erhalte ich wieder denselben Fehler.

    Man sollte wenn schon konsequent sein und "-Wall -pedantic" nehmen, dann wird auch ein Fehler ausgegeben.