Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Comments on Is it OK to use scanf with a void pointer?

Parent

Is it OK to use scanf with a void pointer?

+6
−0

I've created a function that calls scanf passing a void pointer as argument:

void read(const char *format, void *p) {
    scanf(format, p);
}

And tested it with different types:

int n;
read("%d", &n);
printf("read int: %d\n", n);

float f;
read("%f", &f);
printf("read float: %f\n", f);

char s[100];
read("%s", s);
printf("read string: %s\n", s);

I've made these tests in Ubuntu 20.04.3, with clang 10.0.0-4ubuntu1 and gcc 9.3.0. Both were compiled with the options -std=c11 -pedantic-errors -Wall -Wextra -Werror, without any errors/warnings, and both worked fine (all data were correctly read and printed).

But "it worked" doesn't necessarily mean it's correct (specially in C), hence the question: is scanf supposed to work like that (receiving a void pointer and correctly assigning the data to it, according to the format specifier), or is it a big coincidence and should be avoided? Are there any cases that could fail (excluding the obvious ones, such as the format doesn't match the second argument)?


PS: The point here is not to discuss the merits of the read function (if it's useless, or should check the return value of scanf, or should use va_list/vfscanf instead, etc). I'm just interested in knowing if this behaviour of scanf (accepting a void pointer and correctly "guessing" its type based on the specifier) is expected (defined by the standard, for instance). In case it's not, an explanation about why it worked is also appreciated.

History
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

0 comment threads

Post
+5
−0

Void pointers are compatible with every other object pointer type and as mentioned in another answer, 7.21.6/10 speaks of the type of the pointed at object, not the type of the pointer. This is consistent with the rules of effective type/pointer aliasing (6.5/6), which have to be applied as well, since the passed pointer does not necessarily point to a chunk of memory with an object of a declared type (could as well be a void pointer returned from malloc). scanf has to be regarded as a "lvalue" access following the rules of effective type. Examples:

float f;
scanf("%d", &f); // undefined behavior, 7.21.6/10 and 6.5/7
void* v = &f;
scanf("%f", v); // well-defined behavior, object f has declared and effective type float

void* p = malloc(n); // location pointed at by p has no declared type
scanf("%d", p); // well-defined, *p is now to be regarded as effective type int

For scanf to make any sense, it will have to internally cast the passed pointer to a pointer to the type of the specified conversion specifier. Any type information that the passed pointers might have had is lost through the varadic function/va_list parameter passing anyway.

Notably, there's a whole lot of scenarios where scanf can go wrong, so it is mostly to be used for debugging purposes - it is not a function recommended to be used in any professional release. If your program for some reason must use console input, then use fgets as far as possible.

History
Why does this post require moderator attention?
You might want to add some details to your flag.

1 comment thread

Perhaps that's another question, but in `void* p = malloc(n); scanf("%d", p);`, what happens if `n` i... (2 comments)
Perhaps that's another question, but in `void* p = malloc(n); scanf("%d", p);`, what happens if `n` i...
hkotsubo‭ wrote about 2 years ago

Perhaps that's another question, but in void* p = malloc(n); scanf("%d", p);, what happens if n is less than sizeof(int)? I guess it's UB, right?

Lundin‭ wrote about 2 years ago

hkotsubo‭ The C standard is fuzzy and only says that the pointed-at data should be regarded as an array of objects with "a fundamental alignment requirement" (an alignment less than or equal to the greatest alignment supported by the implementation in all contexts). So the alloc functions may grab more memory than specified to suit alignment, and what will happen when writing out-of-bounds of "n" but not out of bounds of this "fundamental alignment object array" isn't clearly specified.