473,320 Members | 2,071 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

printf parameter type wrangling

I'm printing tables of structure members in a terminal and I would like
to use printf with an arbitrary pointer so that the code is smaller and
I don't need to switch over ever possible type.

But the question is - can I pass an arbitrary type (short, double, char *,
etc) to printf cast as a char * (provided the specified format string is
appropriate of course)?

I chose 'char *' because I reasoned it (a pointer) would large enough
to accommodate any primitive type passed as a function parameter.

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

void
printf_member(void *obj, size_t off, const char *fmt)
{
char **p;

p = (char **)((char *)obj + off);

printf(fmt, *p);
}

struct foo {
char c;
float f;
int i;
char *s;
};

int
main(void)
{
struct foo f = { 'c', 2.34f, 100, "hello, world" };

printf_member(&f, offsetof(struct foo, c), "[c]\n");
printf_member(&f, offsetof(struct foo, f), "[%f]\n");
printf_member(&f, offsetof(struct foo, i), "[%d]\n");
printf_member(&f, offsetof(struct foo, s), "[%s]\n");

return 0;
}

Unfortunately this technique does not appear to work as the float member
was not printed properly. Why?

$ gcc -Wall -W -ansi -pedantic -o pa pa.c
$ ./pa
[c]
[0.000000]
[100]
[hello, world]

Thanks,
Mike

Nov 15 '05 #1
15 1635
Michael B Allen wrote on 21/08/05 :
I'm printing tables of structure members in a terminal and I would like
to use printf with an arbitrary pointer so that the code is smaller and
$ gcc -Wall -W -ansi -pedantic -o pa pa.c
$ ./pa
[c]
[0.000000]
[100]
[hello, world]


Sounds too complicated to me... This is how I do :

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

#define FMT_S "%-5s"

#define PRT_C(struct_, field_) \
printf (FMT_S" = '%c'\n" \
, #struct_ "." #field_ \
, struct_.field_)

#define PRT_F(struct_, field_) \
printf (FMT_S" = %f\n" \
, #struct_ "." #field_ \
, struct_.field_)

#define PRT_I(struct_, field_) \
printf (FMT_S" = %d\n" \
, #struct_ "." #field_ \
, struct_.field_)

#define PRT_S(struct_, field_) \
printf (FMT_S" = '%s'\n" \
, #struct_ "." #field_ \
, struct_.field_)

struct foo
{
char c;
float f;
int i;
char *s;
};

int main (void)
{
struct foo f =
{'c', 2.34f, 100, "hello, world"};

PRT_C (f, c);
PRT_F (f, f);
PRT_I (f, i);
PRT_S (f, s);

return 0;
}

Output :

f.c = 'c'
f.f = 2.340000
f.i = 100
f.s = 'hello, world'

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

..sig under repair
Nov 15 '05 #2
In article <pa****************************@ioplex.com>,
Michael B Allen <mb*****@ioplex.com> wrote:
But the question is - can I pass an arbitrary type (short, double, char *,
etc) to printf cast as a char * (provided the specified format string is
appropriate of course)?
No.
I chose 'char *' because I reasoned it (a pointer) would large enough
to accommodate any primitive type passed as a function parameter.
There are two problems here.

First, you are accessing a char * at a place in the struct that does
not necessarily have one. If the object at that location is smaller
than a char * (a char or short perhaps), then you will get some extra
rubbish from another part of the struct or perhaps some (arbitrary)
padding. If it is larger (a double perhaps), you won't get all of it.

Even if the thing there is the same size as a char *, you might (on
some architectures) get some bit pattern that causes an error when
treated as a char * (e.g. when loaded into a address register).
This doesn't happen on most architectures, but might in theory.

Second, you are passing a char * to printf when it expects something
else, and the something else may not be passed in the same way as a
char *. That is almost certainly the cause of the behaviour you're
seeing. If a real float were passed to printf, it would be promoted to
a double, and printf will access a double-sized object at the location
where you have passed only a char *-sized one.

Your char * member works (because it *is* a char *). Your int member
happens to work because int is the same size as char * (and it
wouldn't have been promoted to anything, being an int). And your char
member works because you forgot the % sign and the char happens to be
'c':
struct foo f = { 'c', 2.34f, 100, "hello, world" };

printf_member(&f, offsetof(struct foo, c), "[c]\n");

^ should be %c

The only way to get this to work is to pass printf an argument of the
right type. Since you have to pass in something indicating the right
format for the type, you could instead pass some indication of the
type (e.g. using an enum) and then have a switch in printf_member that
covers all the possible cases.

-- Richard
Nov 15 '05 #3
On Sun, 21 Aug 2005 21:09:37 +0000, Richard Tobin wrote:
The only way to get this to work is to pass printf an argument of the
right type. Since you have to pass in something indicating the right
format for the type, you could instead pass some indication of the
type (e.g. using an enum) and then have a switch in printf_member that
covers all the possible cases.


Drat! Ok. I'll have to use a big switch. I have the type information in
a parallel 'cols' array (stored with the format specifier). I was just
exercising my minimalist instincts.

Thanks for the quick answers as always,
Mike

Nov 15 '05 #4
Drat! Ok. I'll have to use a big switch.


Not really, look at this

#include <stdio.h>

struct foo {
int i; char c; char* s; double f; long l;
} f = { 848, '~', "Stuff to be said", 4.5, 7474l };

print_1(char* fmt, int* data) {
return printf(fmt, *data);
}

print_2(char* fmt, double* data) {
return printf(fmt, *data);
}
int main() {
print_1("%d", &f.i); putchar('\n');
print_1("%c", &f.c); putchar('\n');
print_1("%s", &f.s); putchar('\n');
print_2("%f", &f.f); putchar('\n');
print_2("%ld", &f.l); putchar('\n');

return 0;
}

The point is that ints,chars,char* and the like are passed in one word
(on 32 bit machines) and longs, double etc. are passed as two words. So
you can use one function for the 32 bit data or lesser sized data and
another for the 64 bit sized data.

The problem here is float. Float is actually 32 bit, put is passed as a
double (64 bit). So you can't use either function for floats. Maybe you
could add a third function and then the size of your switch would be
reduced quite a bit.

Nov 15 '05 #5
In article <11*********************@g43g2000cwa.googlegroups. com>,
Pramod Subramanyan <pr***************@yahoo.co.in> wrote:
print_1("%s", &f.s); putchar('\n');
print_2("%f", &f.f); putchar('\n');
That doesn't help much, because you have to know which function to call.

In any case, it's not usually wise to rely on knowing the size of
the datatypes. Especially if you're wrong about it:
The point is that ints,chars,char* and the like are passed in one word
(on 32 bit machines) and longs, double etc. are passed as two words.


Long is 32 bits on most 32-bit processors.

In any case, the big switch is not very big. There aren't that many
built-in datatypes (assuming you don't need to handle pointers other
than strings).

-- Richard
Nov 15 '05 #6
> That doesn't help much, because you have to know which function to call.

1) I've heard of an operator called sizeof. Our learned friend here
perhaps needs to revisit the basics.
2) Moreover, even though our learned friend is not the person asking
question, he has however arbitrarily and pre-emptorily appointed him
sole and final judge of the usefulness of the solution. On what basis,
may I ask?
In any case, it's not usually wise to rely on knowing the size of
the datatypes. Especially if you're wrong about it:
Long is 32 bits on most 32-bit processors.


Its 64 bits on Intel based platforms, which form the biggest chunk of
the market by a LONG (pun unintended) margin, hence the "most". Anyway,
won't a sizeof solve that problem as well?

P.S: Richard, you need to do some REAL programming. Portability issues
aren't as simple as not using the sizes of datatypes. In fact, they're
one of the simplest problems to solve.

Nov 15 '05 #7
"Pramod Subramanyan" <pr***************@yahoo.co.in> writes:
Richard Tobin <ri*****@cogsci.ed.ac.uk> writes:
In any case, it's not usually wise to rely on knowing the size of
the datatypes. Especially if you're wrong about it:
Long is 32 bits on most 32-bit processors.


Its 64 bits on Intel based platforms, which form the biggest chunk of
the market by a LONG (pun unintended) margin, hence the "most". Anyway,
won't a sizeof solve that problem as well?


Type long is 32 bits in every implementation I've see for 32-bit Intel
platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
long long is, of course, required to be at least 64 bits.)

And, Pramod, please don't snip attributions. I had to manually add
the "Richard Tobin .. writes" above.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #8

Keith Thompson wrote:
"Pramod Subramanyan" <pr***************@yahoo.co.in> writes:
Richard Tobin <ri*****@cogsci.ed.ac.uk> writes:
In any case, it's not usually wise to rely on knowing the size of
the datatypes. Especially if you're wrong about it:
Long is 32 bits on most 32-bit processors.


Its 64 bits on Intel based platforms, which form the biggest chunk of
the market by a LONG (pun unintended) margin, hence the "most". Anyway,
won't a sizeof solve that problem as well?


Type long is 32 bits in every implementation I've see for 32-bit Intel
platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
long long is, of course, required to be at least 64 bits.)


VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
bit longs. Given that Intel has something like 85% of the PC-Processor
market, and Windows is used on 80% of those, I stick to my stand. [I
may be wrong about the exact numbers, but they're certainly in the same
region.] And may I add that you haven't seen too many implementations?

Moreover, the whole concept 32/64bit processors is ambiguous. What are
you talking about? Data bus widths, register sizes, memory addressing
capability, or instruction pointer (or program counter if you like)
widths? Simply calling a processor 32bit or a platform 64bit does not
give any real information.

Nov 15 '05 #9
"Pramod Subramanyan" <pr***************@yahoo.co.in> writes:
Keith Thompson wrote:
"Pramod Subramanyan" <pr***************@yahoo.co.in> writes:
> Richard Tobin <ri*****@cogsci.ed.ac.uk> writes:
>> In any case, it's not usually wise to rely on knowing the size of
>> the datatypes. Especially if you're wrong about it:
>> Long is 32 bits on most 32-bit processors.
>
> Its 64 bits on Intel based platforms, which form the biggest chunk of
> the market by a LONG (pun unintended) margin, hence the "most". Anyway,
> won't a sizeof solve that problem as well?
Type long is 32 bits in every implementation I've see for 32-bit Intel
platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
long long is, of course, required to be at least 64 bits.)


VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
bit longs. Given that Intel has something like 85% of the PC-Processor
market, and Windows is used on 80% of those, I stick to my stand. [I
may be wrong about the exact numbers, but they're certainly in the same
region.] And may I add that you haven't seen too many implementations?


I've seen many implementations; few of them run under Windows.
I believe you're mistaken.

Under lcc-win32, long is 32 bits. The following program:

#include <stdio.h>
#include <limits.h>

int main(void)
{
printf("short is %d bits\n", sizeof(short) * CHAR_BIT);
printf("int is %d bits\n", sizeof(int) * CHAR_BIT);
printf("long is %d bits\n", sizeof(long) * CHAR_BIT);
return 0;
}

prints

short is 16 bits
int is 32 bits
long is 32 bits

I get the same output using gcc under Cygwin under Windows XP.

The system in question has an Intel Pentium M processor (IA-32).

Can you demonstrate, using the output of the above program, a C
implementation on a 32-bit Intel processor (define the term "32-bit"
as you like) that has 64-bit long? Please specify the platform, the
compiler, and the actual output of the program.
Moreover, the whole concept 32/64bit processors is ambiguous. What are
you talking about? Data bus widths, register sizes, memory addressing
capability, or instruction pointer (or program counter if you like)
widths? Simply calling a processor 32bit or a platform 64bit does not
give any real information.


Agreed.

These details are only peripherally topical; the point is that
assuming particular sizes for the predefined types is unwise.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #10
Pramod Subramanyan <pr***************@yahoo.co.in> wrote:

Keith Thompson wrote:
"Pramod Subramanyan" <pr***************@yahoo.co.in> writes:
> Richard Tobin <ri*****@cogsci.ed.ac.uk> writes:
>> In any case, it's not usually wise to rely on knowing the size of
>> the datatypes. Especially if you're wrong about it:
>> Long is 32 bits on most 32-bit processors.
>
> Its 64 bits on Intel based platforms, which form the biggest chunk of
> the market by a LONG (pun unintended) margin, hence the "most". Anyway,
> won't a sizeof solve that problem as well?
Type long is 32 bits in every implementation I've see for 32-bit Intel
platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
long long is, of course, required to be at least 64 bits.)


VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
bit longs. Given that Intel has something like 85% of the PC-Processor
market, and Windows is used on 80% of those, I stick to my stand. [I
may be wrong about the exact numbers, but they're certainly in the same
region.] And may I add that you haven't seen too many implementations?


When I compile the following little prog with VSC++ 6.0

#include <limits.h>
#include <stdio.h>

int main(void)
{

printf("bits in char == %d\n", CHAR_BIT);
printf("size of long == %d\n", (int)sizeof(long));
return 0;
}

I get the follwing output:

bits in char == 8
size of long == 4

Which tells me, that long has 4 * 8 Bits which according to Adam Riese would be
32. But I may be wrong.

Moreover, the whole concept 32/64bit processors is ambiguous. What are
you talking about? Data bus widths, register sizes, memory addressing
capability, or instruction pointer (or program counter if you like)
widths? Simply calling a processor 32bit or a platform 64bit does not
give any real information.


You where talking about the size of longs, wheren't you? I suppose that
even on 64 Bit-Architectures longs may be 32 bits wide.

--
Z (zo**********@web.de)
"LISP is worth learning for the profound enlightenment experience
you will have when you finally get it; that experience will make you
a better programmer for the rest of your days." -- Eric S. Raymond
Nov 15 '05 #11
Pramod Subramanyan wrote:
Keith Thompson wrote:
"Pramod Subramanyan" <pr***************@yahoo.co.in> writes:
Richard Tobin <ri*****@cogsci.ed.ac.uk> writes:

In any case, it's not usually wise to rely on knowing the size of
the datatypes. Especially if you're wrong about it:
Long is 32 bits on most 32-bit processors.

Its 64 bits on Intel based platforms, which form the biggest chunk of
the market by a LONG (pun unintended) margin, hence the "most". Anyway,
won't a sizeof solve that problem as well?
Type long is 32 bits in every implementation I've see for 32-bit Intel
platforms. I've seen 64-bit longs on 64-bit Intel platforms. (Type
long long is, of course, required to be at least 64 bits.)


VC++, BC++, LCC and a whole bunch of other platforms on Win32 have 64
bit longs.


I can't comment on BC++ or LCC, but you are wrong about VC++. I know
because I have it installed. To quote from the Fundamental Types page of
the help:

| Sizes of Fundamental Types
|
| Type Size
| bool 1 byte
| char, unsigned char, signed char 1 byte
| short, unsigned short 2 bytes
| int, unsigned int 4 bytes __intn 1, 2, 4, or 8
| bytes depending on the value of
| n. __intn is Microsoft-specific.
| long, unsigned long 4 bytes
| float 4 bytes
| double 8 bytes
| long double(1) 8 bytes
| long long Equivalent to __int64.
|
| (1) The representation of long double and double is identical.
| However, long double and double are separate types.

So unless you are claiming the CHAR_BIT is something other than 8, long
is definitely 32 bits.
Given that Intel has something like 85% of the PC-Processor
market, and Windows is used on 80% of those, I stick to my stand. [I
may be wrong about the exact numbers, but they're certainly in the same
region.] And may I add that you haven't seen too many implementations?
I would not be surprised if Keith has seen rather more implementations
that you.
Moreover, the whole concept 32/64bit processors is ambiguous. What are
you talking about? Data bus widths, register sizes, memory addressing
capability, or instruction pointer (or program counter if you like)
widths? Simply calling a processor 32bit or a platform 64bit does not
give any real information.


Since it was Intel processors that were referred to, the most probable
definition is whether Intel claim them to be 32 or 64 bit processors.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 15 '05 #12
In article <11**********************@g43g2000cwa.googlegroups .com>,
Pramod Subramanyan <pr***************@yahoo.co.in> wrote:
That doesn't help much, because you have to know which function to call.


1) I've heard of an operator called sizeof.


The original poster seemed to want a single function call that worked
for all built-in types. Your proposal didn't do that. If you can fix
it up using sizeof, that might be useful.

The rest of your post consists of insults and a factual error which
others have corrected, so I will not address it.

-- Richard
Nov 15 '05 #13
Sorry, I got this wrong.

Richard, I apologize for the patronizing tone.

Nov 15 '05 #14
"Pramod Subramanyan" <pr***************@yahoo.co.in> writes:
Sorry, I got this wrong.

Richard, I apologize for the patronizing tone.


Since Pramod didn't provide context, I'll mention that what he got
wrong was his claim that type long is commonly 64 bits on 32-bit Intel
platforms.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #15
"Pramod Subramanyan" <pr***************@yahoo.co.in> wrote:
Sorry, I got this wrong.

Richard, I apologize for the patronizing tone.


Got _what_ wrong? _What_ patronising tone? I don't recall you being
patronising to me... oh, wait, maybe you were patronising to Mr.
Heathfield?

It _is_ possible to get Google Groups Broken Beta to quote, you know.

Richard
Nov 15 '05 #16

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Pontus F | last post by:
Hi I am learning C++ and I'm still trying to get a grip of pointers and other C/C++ concepts. I would appreciate if somebody could explain what's wrong with this code: ---begin code block--- ...
11
by: Sam Wilson [Bentley] | last post by:
If you pass a C++ object by value as an argument to a function which has a variable-length argument list (...), the MSVC7 C++ compiler does not call the object's copy constructor and will not...
3
by: Hans Ginzel | last post by:
Hello, let us consider function int foo(char *name, void *data) { ... printf(name, data); /* Should be *data? */ ... }
8
by: scrodchunk | last post by:
I'm having a weird problem with printing bytes in hex format. I have a bunch of print statements that are working okay, then using the identical formatting later in my code I get some thing where...
12
by: John Devereux | last post by:
Hi, I would like to know if their is a conversion specifier, or other method, that will allow me to not use particular arguments to printf. Failing that, is it permissable to simply "not use"...
19
by: v4vijayakumar | last post by:
why the following statement dumps the core(Segmentation fault)? printf("%s\n", __FILE__);
10
by: lovecreatesbeauty | last post by:
Is parameter type conversion required for the 2nd argument on printf("%p", (void *)&i); ? But one would never call memcpy like: memcpy((void *)pi, (void *)pj, sizeof *pj); /*memcpy((void *)pi,...
34
by: Old Wolf | last post by:
Is there any possible situation for printf where %hd causes a different result to %d, and the corresponding argument was of type 'short int' ?
2
by: java | last post by:
Hi: There is an introductory diagram for those confused by javascript type wrangling (i.e., runtime type conversion by the javascript interpreter). http://mollypages.org/misc/jstypes.mp ...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.