-5

[My Question is little weird but it's not right to change it now as it is answered with good explanation but I am Editing it with [Update].......[Update End] tag to avoid confusion to upcoming visitors to my post]

C

#include<stdio.h>
int main()
{
    float *q=NULL;
    
    printf("%f\n",q);
}

OUTPUT

0.000000
  • In C output is 0.000000
  • so here q is float type null pointer or still q is (void *) type null pointer ?
  • I feel it is (void *) type.
  • so mismatch in format(%f) and argument(void*) invoke undefined behaviour and lead to such error type output

[Update] But you will fill answer to my own Question such stupid Question I asked

basically I am confused that I feel I have to print something float type or void type but point is I am printing address and so it just foolish to use %f to use to print address.

Obviously q is float type pointer only what I feel is totally wrong

generally we use %u to print address of any type of variable(int,char,float) but for pointer we should use %p

[Update End]

C++

#include<iostream>
int main()
{
    float *q=nullptr;
    std::cout<<q;
}

OUTPUT

0
  • In C++ give output 0
  • I think it's fine as it give address of 1st memory block as pointing to nothing
  • and if q is nullptr_t type then C++11 should give ambugity error means here q is float type nullptr.

[Update]

The C and C++ standards both specify that a null pointer constant compares equal to zero - they say nothing about what is at that address.

obviously q is float type nullptr only

[Update End]

So if my both assumptions are correct then why in C++ nullptr changing it's type to float type from nullptr_t but in C NULL is not changing it's type from (void ) to (float) ?

[Update]

My first assumption in 1st example of C that q is (void*) type is already wrong and 2nd Assumption that in 2nd ex. of C++ that q is nullptr_t is also wrong.

So Summarize all here

I am trying to compare that this is happening in C and this is happening in c++ and I feel these things are contradict to each other

but in reality while in C I am using %f to print address of pointer that's first mistake. In C++ code all I think is all right except One thing that it is wrong to assume that null pointer points to 1st block of memory which is 0th as it is not specify in c standard it just say that nullptr constant compares to 0 when evaluate.

so tons of mistake in question only so it is not proper question

[Update End]

Abhishek Mane
  • 619
  • 7
  • 20
  • 19
    `printf("%f\n",q);` is undefined behavior in C. You are lying to `printf` about the type of the argument. – NathanOliver Mar 30 '21 at 13:27
  • 1
    In the C code, you have explicitly directed `printf()` to *assume* `q` is a `float`, using the `%f` format - but `q` is not a `float` hence undefined behaviour. In C++, output streams provide overloaded `operator<<()` functions that accept the stream and a second argument. One of those overloads accepts `void *`, and that is called by `std::cout << q` since. `float *` can be implicitly converted to `void *` Since `q` is a nullptr, it is a null pointer constant, which has a value that compares equal to zero - one obvious way to implement the `operator<<()` is to print a null pointer as zero. – Peter Mar 30 '21 at 13:38
  • @NathanOliver thanks for answering but I am not getting you can you explain it in brief please ? – Abhishek Mane Mar 30 '21 at 13:41
  • 4
    `q` is not a double. But `"%f"` expects the parameter is a double. Hilarity and hijinks ensue (aka *undefined behavior*). – Eljay Mar 30 '21 at 13:42
  • @NathanOliver then format specifier should be %d and more accurate is %u right ? – Abhishek Mane Mar 30 '21 at 16:17
  • @Peter I got my error in C, So I should use %d and %u (more accurate) right ? and in C++ I can't get you clearly but I concluded that q is float * type nullptr when we do cout< – Abhishek Mane Mar 30 '21 at 16:33
  • 1
    @AbhishekMane - No, on both counts. (1) If the type specified in the printf format string differs from the type of the corresponding argument (apart from a few exceptions involving implicit type conversion, not relevant here), the behaviour is undefined. A pointer is not an integral type, so formatting one using `%d` and `%u` is also undefined behaviour. Use the `%p` format AND print `(void *)p`. (2) The C and C++ standards both specify that a null pointer constant compares equal to zero - they say nothing about what is at that address. – Peter Mar 30 '21 at 20:01
  • Tip: Concerning DVs. Using both tags C and C++ attract DVs as the questions rarely _need_ to apply to both languages. Best to focus on one. – chux - Reinstate Monica Mar 31 '21 at 15:59
  • @chux-ReinstateMonica Noted – Abhishek Mane Apr 01 '21 at 08:15
  • @chux-ReinstateMonica stackoverflow.com/q/67772282/11862989 can you answer this question please – Abhishek Mane Jun 02 '21 at 12:25

2 Answers2

3
printf("%f\n",q);

The format specifier %f requires that the type of the passed object is of type double (float argument will be converted implicitly, so that is OK too). You passed a float* which is the wrong type. Passing argument of wrong type into printf results in undefined behaviour.

printf("%p",q);

This one is a bit more subtle, but %p specifier requires the type of the argument to be void*. float* is still the wrong type, so behaviour is still undefined.

You should be more careful about using the correct format specifier and type of argument. The C formatted I/O API is very unforgiving.


In C++ give output 0

Note that whether you get output of 0 or something else depends on what value the system uses to represent the null pointer.

why in C++ nullptr changing it's type to float type from nullptr_t

nullptr never "changed its type to float type" in your example. In float *q=nullptr, the implicit conversion is to the type float*.

but in C NULL is not changing it's type from (void ) to (float) ?

Type of the NULL macro is not void in C. It can be an integer constant 0, or such constant converted to void*. Both of those could be implicitly converted to any pointer type. That's what happens in float *q=NULL.

So, in both languages you implicitly converted null to a pointer type.


Regardless of what types can be implicitly converted to which types, variadic arguments are not implicitly converted to the types required by the format string because those types are unknown to the compiler1 2.

1 There are conversions such as from float to double that I mentioned, but those are not dependent on the format specifiers.

2 If the format string is constant, some compilers do helpfully diagnose your mistakes, but they aren't required to do so.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • *but %p specifier requires the type of the argument to be `void*`. `float*` is still the wrong type*. That does not make sense. Any pointer type can be converted to `void*`. – R Sahu Mar 30 '21 at 13:48
  • @RSahu They can be converted, but if you don't do the conversion, then the ability to do so is irrelevant. – eerorika Mar 30 '21 at 13:49
  • 2
    @RSahu It isn't converted when passed as a variadic parameter. – Kevin Mar 30 '21 at 13:49
  • 1
    And it shouldn't be converted when passed as a variadic parameter, because `scanf` does need a real `float*`. – MSalters Mar 30 '21 at 13:57
  • @RSahu "Any pointer type can be converted to void*" --> Function pointer conversion to `void*` may lose information as `void*` may be narrower. Perhaps you are thinking of object pointer conversion to `void *`? – chux - Reinstate Monica Mar 30 '21 at 15:44
  • @chux-ReinstateMonica On systems that support conversions from function pointer to `void*`, the conversion is lossless. On other systems such conversion is ill-formed. – eerorika Mar 30 '21 at 15:47
  • @eerorika I got my error in C, So I should use %d and %u (more accurate) printf("%u",q); right ? – Abhishek Mane Mar 30 '21 at 16:35
  • @eerorika in C++ q is float * type nullptr means it is pointing to 1st block of memory or 0th adress (generally assume) of float type so when cout< – Abhishek Mane Mar 30 '21 at 16:37
  • 1
    @AbhishekMane There is no correct format specifier for `float*`. You can convert it to `void*` after which you can use `%p`. There is no guarantee that null is represented by address 0. – eerorika Mar 30 '21 at 16:42
  • @eerorika printf("%p",(void*)p); output 0000......16 zeroes what these 16 zeroes represent ? why total 16 ? – Abhishek Mane Mar 30 '21 at 16:46
  • 1
    @AbhishekMane A pointers represents a memory address. What you see is some implementation defined textual representation of that address. Most likely, they are 16 hex digits. 16, probably because they are enough to represent any pointer value on your system. – eerorika Mar 30 '21 at 16:49
  • @eerorika float a=3.5; float *p=&a; printf("%d\n",p); printf("%p",(void*)p); output 6487572, 000000000062FE14 from this I think %d,%u works fine might be I am wrong but please put some extra light on this. – Abhishek Mane Mar 30 '21 at 16:56
  • 1
    @AbhishekMane You think wrong. It doesn't work. The behaviour of the program is undefined. – eerorika Mar 30 '21 at 16:58
  • @eerorika but %p is format specifier for NULL only but every float* need not to be points to NULL So what's the point of using %p at every time – Abhishek Mane Mar 30 '21 at 17:02
  • 1
    @AbhishekMane You're mistaken %p is not a format specifier for "NULL". %p is for `void*`. The point of using %p is to get a textual representation of a pointer. – eerorika Mar 30 '21 at 17:16
  • @eerorika yeah you are right and thanks for your help and I really mean it. – Abhishek Mane Mar 30 '21 at 18:44
  • @eerorika but in C++ int a=nullptr; cout< – Abhishek Mane Mar 31 '21 at 07:29
  • 1
    @AbhishekMane "please remove downvote" --> I cannot remove a DV as I have not DV'd the question. Please do not assume who DV'ed. Do not use comments under an answer for such requests. Both actions encourage question DVs. – chux - Reinstate Monica Mar 31 '21 at 15:42
  • @chux-ReinstateMonica Noted – Abhishek Mane Apr 01 '21 at 08:17
  • @eerorika I come too this question after lot of days. Now I can able to understand your answers clearly to my confusion at that time. Thanks your answer is accepted. – Abhishek Mane May 14 '21 at 16:25
3

The pointer isn't changing type. In the cout version, you're letting the system print the pointer value natural. In the printf version you're forcing a %f. Change the format string to %ld and you'll get different results.

printf doesn't know a thing about what you're passing as arguments. It trusts the programmer knows what he's doing.

--- Edit here to answer more questions ---

You're right that %lu is probably better than %ld. I suppose it's possible that you'd have an address with the most significant bit set (which would mean %ld would think it's negative).

Yes:

float * q = nullptr;

Means q is all-zero.

Cout knows what is being printed and (usually) does the right thing. It is rare to use format specifiers unless you're very specifically controlling it (like number of digits to use when printing out floats & doubles). I use it to set default output of bools to print true or false instead of 1 or 0. But generally speaking, you get sane values when using cout without any extra work or thought necessary.

Joseph Larson
  • 8,530
  • 1
  • 19
  • 36
  • %d,%ld and more accurate %u am I right ? and also tell me that " in C++ q is float * type nullptr means it is pointing to 1st block of memory or 0th adress (generally assume) of float type so when cout< – Abhishek Mane Mar 30 '21 at 16:39
  • @AbhishekMane I'll update my answer a little, as it's getting too long to put in a comment. – Joseph Larson Mar 30 '21 at 17:18