3

Is this undefined behaviour? (Because the strings "True", "False" and "Error" only exit within the blocks and are destroyed when a block is exited):

char *p;
if (var1) {
    p = "True";
} else if (var2) { 
    p = "False";
} else {
    p = "Error";
}
printf("%s\n", p);

The same applies for the switch statement I guess. Then how could I express the logic above?

Sub question: Is this also undefined behaviour? :

struct bar {
    int i;
    double d;   
}

struct bar *barptr;
if (var1){
    barptr = &(struct bar) { 0, 0.0 };
} else {
    barptr = &(struct bar) { 5, 40.3 };
}
printf("%d", barptr->i);
3
  • 4
    assigning a string literal to a char * ptr is (if not undefined) certainly unwise behaviour, as it might result in people attempting to write to it. Use char const * instead. Commented Oct 20, 2014 at 10:37
  • @TomTanner so when is a good time to use char *? Only to point at (iterate over) an array of chars? Commented Oct 20, 2014 at 11:01
  • You should use char * to point only to arrays of characters that you can alter. Commented Oct 20, 2014 at 11:13

6 Answers 6

5

There is no any undefined behaviour. String literals have the static storage duration. There is only invalid code (that was before you edited your post) because you forgot to specify a condition in statement

else if

According to the C Standard (6.4.5 String literals)

6 In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.78) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence

As for the compound literals then the code snippet indeed has undefined behaviour. According to the C Standard (6.5.2.5 Compound literals)

5 The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

Take into account that there must be

barptr = &(struct bar) { 0, 0.0 };

The code snippet would be valid if you would write

struct bar {
    int i;
    double d;   
};

struct bar bar;
if (var1){
    bar = (struct bar) { 0, 0.0 };
} else {
    bar = (struct bar) { 5, 40.3 };
}
printf("%d", bar.i);
Sign up to request clarification or add additional context in comments.

2 Comments

and what about the compound literal?
Thanks, I corrected the barptr = &(struct bar) {...}
1

As far as 'this code snippet' is concerned, there is no issue. (Removed the useless/incomplete if else check from your code :-) )

int main ()
{
  char *p;
  int var = 0;

  if (var){
    p = "True";
  } else {
    p = "False";
  }

  printf("%s\n", p);
  return 0;
}

if var = 0, it will print "False", else it will print "True".

5 Comments

But that's the problem with undefined behaviour, if it works it does not mean that it is GUARANTEED to work. Even returning a pointer to a compound literal declared inside some function might work. But its not guaranteed. (correct me if I am wrong)
@user10607 You are mistaken, a C compiler is required to include all strings that -could ever- be used by the program into the programs code memory or static data memory. It does not matter if they are ever used or not. Strings are not like normal variables, they exist globally throughout the whole program, only the pointers to them go out of scope and as you are using p as a pointer to them they will remain valid through that for as long as p is in scope.
@Vality is not this potentially a lot of wasted memory? Many of the strings are going to be used only once so why store them all?
@user10607 Because if we do not store them all the program will not be able to get to them when it needs them which could be at any point. Fortunately in a modern OS, it will be smart enough to swap them out to hard disk when they are not being used as to not waste memory, but they will still logically be mapped into memory. Your point is indeed correct however, having many strings statically allocated like that is very wasteful of both memory and address space, it is much better, if your program has much text to use a data file containing the strings and then read them out of that when needed
Also, it is a common compiler optimization to use "string pooling", meaning that if the same string literal occurs at several places in the program, it will only be allocated once.
1

String literals have static storage duration.

6.4.5. p6 In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.78)The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.

Static storage duration means that variables are initialized at program startup and are valid throughout the program.

You first example does not have undefined behavior.

However in the second example you try to point to compound literals which have automatic storage duration, this means that once you exit the if statement they don't exists anymore.

6.5.2.5. p5 The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

struct bar *barptr;
if (var1){
    barptr = &(struct bar) { 0, 0.0 }; 
} else {
    barptr = &(struct bar) { 5, 40.3 };
}                                      

barptr->i = 123 ;   //UNDEFINED BEHAVIOR

7 Comments

Ok, and what is the scope of a variable with static storage? So if some function of mine returns a pointer to a string, would that be safe?
@user10607 Yes, that will be save if you return a string literal.
I see... so returning a pointer to a string literal is not safe?
@user10607 No, that is safe. You can't return anything else but a pointer in that case.
Say a function declares a pointer to a string literal with char const *p that tells the compiler that I want a string literal and so it stores the string for as long as the program exists. And so I can move the pointers to this string around (return and pass them to functions). But for this I have to specify the const type qualifier. Does this sound fine to you? :)
|
0

Typically the string literal ("True" and "False") will be stored in the data section, in a read-only page

So its not undefined behaviour.

1 Comment

Or rather, it is not undefined behavior because the C standard says that string literals have static storage duration (C11 6.4.5). String literals may end up in different memory segments from system to system.
0

This is well defined. As by standard:

6.4.5 String literals

Syntax

[...]

Description

2 A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in "xyz". A wide string literal is the same, except prefixed by the letter L.

And so your assignments are stringliterals. And About Stringliterals life time the ISO/IEC 9899:TC3 says:

[...]

5 In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.

So you can see a String literal exists from the starting up to the termination of your programm.

And now you also know they are such "string literals"

So you can be sure.

It is absolutly well defined.

Comments

-2

This is undefined behaviour right? (Because the strings "True", "False" and "Error" only exit within the blocks and are destroyed when a block is exited)

No. You should look on the variable, not on literals. Your char* p exists when you call it in printf.

1 Comment

-1 This is nonsense. You should not look at the variable. char* p; if(something){ char arr[]="hello"; p=arr; } puts(p); has undefined behavior.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.