2

Is there any possible way in C (by using any function or any such kind) so that we can print the contents in a structure of different datatypes using a single line? Say for eg:

typedef struct ABC{
   int a;
   char b;
   long c;
}ABC1;

To print this we need to write: printf("%d %s %ld",ABC1.a,ABC1.b,ABC1.c)

Any other method so that i can print like printf("????",????ABC1)??

Parvathi
  • 87
  • 2
  • 7
  • `printf()` does not have some magical format specifier that can correctly recognise an arbitrary user-defined struct type, and cannot work out the type of an argument unless you correctly specify it in the format string. You can create a function which knows how to print a `struct ABC` with the desired format, but it will not know how to print some other struct type. – Peter Dec 21 '15 at 07:35
  • 2
    The format string should be `"%d %c %ld"` to match the actual arguments. Answer to the actual question is no, C has no "introspection" capability to figure out at runtime what a `struct` is made up of. To get and idea of the difficulties, see [Is there a way to print struct members in a loop without naming each member in C?](http://stackoverflow.com/a/27497861). – dxiv Dec 21 '15 at 07:38
  • @dxiv Why would it have to figure it out in run-time? Simply do it in compile-time, see my answer below. – Lundin Dec 21 '15 at 09:11

6 Answers6

2

First of all, the code probably wouldn't compile. You have defined ABC1 to be a typedef of the ABC struct. ABC1 is not a variable, so you cannot view the contents of ABC1.a.

Assuming you created a variable of type ABC1, you cannot "dump" the contents of the structure in a "logical" format using printf. The printf function receives a memory address and displays its contents based on the string given. The printf function cannot know the format of the structure if it only has a pointer to the memory (i.e. a bunch of bytes with no way of knowing what "type" of bytes).

D G
  • 529
  • 4
  • 7
2

No. Best solution would be to write a method like:

  1. void printABC(struct ABC*) or
  2. char* abcToString(struct ABC*) (and then print via %s).

Option 2 is probably better and can be used eg to write to file and so on.

John3136
  • 28,044
  • 4
  • 47
  • 66
1

No, printf() only has support for format specifiers for pre-defined data types, not for user defined data type (struct). Moreover, printf() also has no way to automatically learn the types of member variables of your struct.

You need to roll your own function to achieve the task you want.

Sourav Ghosh
  • 130,437
  • 16
  • 177
  • 247
1

Just like @john3136 said .

but here is an example for 1 .

void printABC(ABC1 *ABC) /* can also use 'struct ABC*' */
{
   printf("%d %c %ld",ABC->a,ABC->b,ABC->c);
   /* Equivalent to the below */
   /* printf("%d %s %ld",(*ABC).a,(*ABC).b,(*ABC).c); */
}

So now everytime you want to print the whole thing you just type something like

    ABC1 xyz;

    /* fill xyz here*/

    printABC(&xyz);

and It should type everything inside of ABC1 in one line.

P.P
  • 112,354
  • 20
  • 166
  • 226
Malek
  • 1,175
  • 1
  • 7
  • 11
  • 2
    Please be careful: you pass **`ABC`** as a pointer, and then use `ABC` **`1`** as an object. You should fix before downvotes fall... – Serge Ballesta Dec 21 '15 at 08:00
  • `void printABC(struct *ABC)` This won't even compile. If you meant `void printABC(struct ABC *abc)` maybe, then `ABC.a` would need to be `abc->d` and so on. – dxiv Dec 21 '15 at 08:20
  • 1
    P.S. With all due respect to @l3x who just edited the answer for the better, but the printf format is still wrong (should be `%c` not `%s`) and the subsequent `printABC(&ABC1);` won't compile since `ABC1` is a typedef. Honestly, I don't understand whomever upvoted this answer *after* my previous comment *after* @SergeBallesta's initial comment. – dxiv Dec 21 '15 at 08:38
  • 1
    @dxiv Sorry, I missed a couple. Should be fine now. – P.P Dec 21 '15 at 08:42
  • @l3x Looks good to me now. Though it's basically *your* answer at this point, if you compare the *before* and *after*. That was a commendable rescue op ;-) – dxiv Dec 21 '15 at 08:52
  • indeed its a whole new answer ! thanks guys . sincere apologies I haven't slept for 2 days but felt like answering some questions . – Malek Dec 21 '15 at 08:54
1

If you are using a somewhat modern C compiler, you can use a type-generic macro:

#include <stdio.h>

typedef struct {
   int a;
   char b;
   long c;
} ABC;

// printf conversion specifiers:
#define CS(x)   \
  _Generic((x), \
    int:  "%d", \
    char: "%c", \
    long: "%ld")


int main (void)
{
  ABC abc = {1, 'a', 2};

  printf(CS(abc.a), abc.a); printf(" ");
  printf(CS(abc.b), abc.b); printf(" ");
  printf(CS(abc.c), abc.c); printf(" ");

  return 0;
}
Lundin
  • 174,148
  • 38
  • 234
  • 367
1

Glibc allows you to establish your own format specifiers for printf and family to let you print UDTs, which would not otherwise be possible, through some extensions.

#include <stdio.h>
#include <printf.h> /* For PA_POINTER */

struct MyStruct
{
    int a;
    double b;
};

struct print_info;
int handler(FILE *stream, const struct print_info *i, 
        const void* const *args)
{
    const struct MyStruct *ptr = *( (const struct MyStruct**) (*args) );
    int rc = fprintf(stream, "a: %d, b: %f\n", ptr->a, ptr->b);

    return rc;
}

int print_arginfo (const struct printf_info *info, size_t n,
                      int *argtypes)
{
  if (n > 0)
    argtypes[0] = PA_POINTER;
  return 1;
}

int main(void)
{
    struct MyStruct s = {55, -3.14};
    /* We're gonna use the M specifier */
    int spec = 'M';
    int rc = register_printf_function(spec, handler, print_arginfo);

    if (rc != 0)
        return 1;

    printf("%M", &s);

};

You may find the documentation here.

edmz
  • 7,970
  • 2
  • 22
  • 45