Reputation: 3774
After reading this, my understanding is that the following program should invoke UB. Am I right?
int main(void)
{
char *ptr = "ABCD";
ptr = 'A';
printf("%c\n", ptr);
}
Thanks.
Upvotes: 2
Views: 147
Reputation: 145277
You are correct, the posted code does invoke undefined behavior in multiple ways.
You probably do not want to work in a company where such code is considered OK.
When I compile the code with my default clang
options, I get 4 warnings:
clang -O2 -funsigned-char -std=c11 -Weverything -Wno-padded -Wno-shorten-64-to-32 -Wno-mis\
sing-prototypes -Wno-vla -Wno-missing-noreturn -Wno-sign-conversion -Wno-missing-variable-\
declarations -Wno-unused-parameter -Wwrite-strings -lm -o ub2 ub2.c
ub2.c:3:11: warning: initializing 'char *' with an expression of type 'const char [5]' dis\
cards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
char *ptr = "ABCD";
^ ~~~~~~
ub2.c:4:9: warning: incompatible integer to pointer conversion assigning to 'char *' from \
'int' [-Wint-conversion]
ptr = 'A';
^ ~~~
ub2.c:5:5: warning: implicitly declaring library function 'printf' with type 'int (const c\
har *, ...)'
printf("%c\n", ptr);
^
ub2.c:5:5: note: include the header <stdio.h> or explicitly provide a declaration for 'pri\
ntf'
ub2.c:5:20: warning: format specifies type 'int' but the argument has type 'char *' [-Wfor\
mat]
printf("%c\n", ptr);
~~ ^~~
%s
4 warnings generated.
3 of these warnings indicate possible undefined behavior:
assigning an integer value to a pointer 'A'
invokes undefined behavior except for the integer constant 0
which is converted to the null pointer. Some systems will trigger an exception for some values, some will just store the integer value into the location of the pointer, one cannot rely on it. you will see code like ptr = (char*)0x0040006C;
that may compile correctly on the specific system for which it is tailored, but it only works for specific compiler / target combinations.
passing a pointer for a %c
conversion specifier is explicitly described as invoking undefined behavior in the C Standard. Pointers might be passed to printf
in a different way than int
values, in a different set of registers for example, so printf
would not receive the value of the pointer to print as a character. This value might not be 'A'
anyway, even if properly cast back as (int)ptr
.
calling printf
without a proper declaration in scope invokes undefined behavior. The implicit prototype inferred by the compiler from the arguments passed might be incompatible with the varargs calling convention used by printf
. You must include <stdio.h>
or at least provide a valid prototype before calling printf
.
On a lesser note, there are some more remarks:
"ABCD"
is a string literal. It must not be written to. For compatibility with tons of legacy code, the C Standard (relunctantly) gives it a type of char[5]
where it should really be const char[5]
. This explains why you do not get a warning by default on char *ptr = "ABCD";
, but it is wise to allow the compiler to be stricter than the Standard and warn the programmer about this. const
correctness may require extensive changes in large projects, but will prevent potential undefined behavior and improve the compilers ability to optimise code.
returning 0
from main()
is implicit since C99, but it is considered cood style to have an explicit return 0;
to indicate success.
Upvotes: 3
Reputation: 26757
A c-string is a series of char. Terminate by the char '\0'
.
char *ptr = "ABCD";
Create an array of 5 chars. {'A', 'B', 'C', 'D', '\0'}
somewhere in static memory and assign the address of the first char (aka. 'A'
) to ptr.
When you do
ptr = 'A';
You assign the value of 'A'
to ptr
, It's not a valid pointer or c-string so de-referencing the pointer cause an undefined behavior.
Plus, C is a typed language you can't put anything in anything. It's no guarantee that after assign 'A'
to ptr
. That ptr
will be equal to 'A'
. ptr
has type char *
, 'A'
has type char
. You can't mix these types.
char *ptr = 'A';
if (ptr == 'A') // this is undefined behavior
*ptr; // same here
Here what you must write if you want do what you try.
char c = 'A';
char *ptr = &c; // here ptr is not a valid c-string, it's just a pointer for one char
printf("%c", *ptr);
Upvotes: 1
Reputation: 434
Here ptr points to a location in the data section(Read-only) section of the program. You modified ptr='A'; Here ptr points to ascii value i.e 65 .So ptr points to the value at 65 location hence an undefined behavior
Upvotes: -1