C: %.*s passing unsigned long as int to .*

mogbo

Banned
Hallo,
habe ein etwas müßiges Problem, was ohne Fehler ausgegeben wird, ich mir aber nicht sicher bin ob es wirklich die richtige Lösung ist:

Mein Programm etwas vereinfacht:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct node {
   int zahl;
   char array[55];
   struct node * next;
};

struct node * head = NULL;

int
main(int argc, char * argv[])
{
   head = malloc(sizeof(struct node));
   struct node * current = head;

   int i;

   for (i = 0; i <= argc; i++) {
     head->zahl = i;

     snprintf(head->array, sizeof(head->array), "%s", argv[i]);

     head->next = malloc(sizeof(struct node));
     head = head->next;
   }
   head = NULL;
   i = 0;

   while (current->next != NULL && i < argc) {

     if (current->zahl == 0) {
     /*
      * do nothing
      */

     } else {
       printf("[%i]\t%.*s\n", current->zahl, (int) sizeof(current->array), current->array);
     }
     current = current->next;
     i++;
   }

   free(head);
   return 0;
}

Speziell dieser Teil:
Code:
     } else {
       printf("[%i]\t%.*s\n", current->zahl, (int) sizeof(current->array), current->array);
     }
Ich möchte das %s (current->array) die maximale Länge sizeof(current->array) hat, übergebe aber mit sizeof(current->array) einen unsigned long an %.*s (einen int?).

Ist meine Lösung eine gute Idee mit "(int) sizeof(current->array)" oder sollte ich mir einen anderen Wert einprägen?

Code:
#include <stdio.h>

int
main(void)
{
  printf("unsigned long: %lu\n", sizeof(unsigned long));
  printf("int: %lu\n", sizeof(int));


  return 0;
}

ergibt:
Code:
unsigned long: 8
int: 4

Was wäre die Musterlösung?
 
übergebe aber mit sizeof(current->array) einen unsigned long an %.*s (einen int?).

Ich glaube, dein wesentliches Problem ist dein Verständnis von Formatierungen: %.*s ist kein int, sondern ein String - daher das "s". Dem String ist der Datentyp, den er ausgeben soll, aber völlig wurscht.
 
auf Position von
Code:
#include <stdio.h>

int
main(void)
{
  char eins[] = "Hallo Welt\n";
  printf("%.*s", sizeof(eins), eins);

  return 0;
}

Compiling:
Code:
cc -O2 -pipe  -o test7 test7.c
test7.c:7:12: warning: field precision should have type 'int', but argument has type 'unsigned long' [-Wformat]
  printf("%.*s", sizeof(eins), eins);
  ~~^~  ~~~~~~~~~~~~
1 warning generated.

Lösung (zumindest ein Workaround):
Code:
#include <stdio.h>

int
main(void)
{
  char eins[] = "Hallo Welt\n";
  printf("%.*s", (int) sizeof(eins), eins);

  return 0;
}

Ich glaube, dein wesentliches Problem ist dein Verständnis von Formatierungen: %.*s ist kein int, sondern ein String - daher das "s".
Sry, dachte man versteht was ich meine

Das %s einen String will ist mir klar, aber ich will die Länge des Strings beschränken, darum %.*s
 
Hi,

sizeof liefert einen size_t zurück, das ist in der Regel ein unsigned integer. Das Präzisionsargument erwartet einen int.
Daher würde ich sagen: der cast nach int ist korrekt.

Rob
 
sizeof liefert einen size_t zurück, das ist in der Regel ein unsigned integer.
Code:
#include <stdio.h>

int
main(void)
{
  printf("unsigned long: %lu\n", sizeof(unsigned long));
  printf("int: %lu\n", sizeof(int));
  printf("sizeof(sizeof(int)): %lu\n", sizeof(sizeof(int)));
  printf("sizeof(unsigned int): %lu\n", sizeof(unsigned int));


  return 0;
}

Wäre das nicht der Gegenbeweis? Ausgabe:
Code:
unsigned long: 8
int: 4
sizeof(sizeof(int)): 8
sizeof(unsigned int): 4
 
Ich habe nur die Spezifikation gelesen, alles andere interessiert mich eigentlich auch nicht.
size_t ist offenbar auch 8 Byte breit, also breiter als unsigned int.

Dennoch: der cast ist in meinen Augen korrekt so.

Rob
 
sizeof liefert einen size_t zurück, das ist in der Regel ein unsigned integer.

Der Standard sagt dazu:
size_t
which is the unsigned integer type of the result of the sizeof operator

`size_t` ist also ein Datentyp, der die Größe des größtmöglichen Objektes (lies: Speichersegment) auf der Platform darstellen kann. Auf 64 Bit Plattformen ist es also ein 64 Bit Integer. Linux und BSD sind LP64-Systeme, das heißt `long` und Zeiger haben 64 Bit (= 8 Byte), `int` hat nur 32 Bit (= 4 Byte). Microsoft hat übrigens beschlossen, dass Windows aus Gründen der Abwärtskompatibilität ein P64-System ist, dort ist `sizeof(long) == sizeof(int)`, was C den neuen Typ `long long` beschert hat.

Das Präzisionsargument erwartet einen int.
Daher würde ich sagen: der cast nach int ist korrekt.

Dies ist trotzdem korrekt, nur dass eben nicht nur das Vorzeichen sondern auch der Datentyp selbst verändert werden.
 
Habs aus Neugier nochmal gegengetestet:
Code:
#include <stdio.h>

int
main(void)
{
  unsigned long a = 0;
  int b, n;

  while (b == a) {
      a++;
      n++;
      b = (int) a;
      if (n == 10000) {
          printf("a: %lu ; b: %i\n", a, b);
          n = 0;
      }
  }
  printf("a: %lu ; b: %i\n", a, b);

  return 0;
}


Die Ausgabe bestätigt euch :)
Code:
...
a: 2147460000 ; b: 2147460000
a: 2147470000 ; b: 2147470000
a: 2147480000 ; b: 2147480000
a: 2147483648 ; b: -2147483648

Nochmals vielen Dank!
 
Zurück
Oben