473,748 Members | 10,737 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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(v oid *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 1667
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************ *********@g43g2 000cwa.googlegr oups.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_Keit h) 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_Keit h) 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

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

Similar topics

11
55580
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--- #include "stdio.h" #include "string.h" void printText(char c){
11
2340
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 complain if the copy constructor is private. 1) Is this part of the C++ language definition? What is the thinking behind it? 2) In any case, how can I catch at compile time any callers that try to
3
3229
by: Hans Ginzel | last post by:
Hello, let us consider function int foo(char *name, void *data) { ... printf(name, data); /* Should be *data? */ ... }
8
20171
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 the formatting and type are ignored. At one spot in my code I'm loading an array with random bytes int i; char byte_block;
12
7628
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" the parameter if it is at the end of the parameter list? For example,
19
5463
by: v4vijayakumar | last post by:
why the following statement dumps the core(Segmentation fault)? printf("%s\n", __FILE__);
10
2367
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, (void *)pj, sizeof *pi);*/ /*size of what?*/ By the way, will the 3rd argument of memcpy follow the size of the 1st or the 2nd argument? If it follows the size of the 1st argument, unwanted data in the memory area pointed by the 2nd parameter...
34
15967
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
2311
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 It's not comprehensive but covers most common scenarios.
0
8830
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
9321
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9247
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8242
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6074
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4874
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3312
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2782
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2215
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.