What are the advantages of using "{}" for casting in C Language?
Asked Answered
B

2

4

I am trying to understand why use this casting style in ProcessHacker Code.

 RtlSetHeapInformation(
            PhHeapHandle,
            HeapCompatibilityInformation,
            &(ULONG){ HEAP_COMPATIBILITY_LFH }, // HEAP_COMPATIBILITY_LFH = 2UL 
            sizeof(ULONG)
            );

What are the advantages of using "{}" for casting? Does it work in C and C++?

&(ULONG){ HEAP_COMPATIBILITY_LFH }, // HEAP_COMPATIBILITY_LFH = 2UL 
Bedesman answered 6/3, 2021 at 9:27 Comment(3)
Simplifies macros. You can the same scheme for scalar types and structs. Both 'int x=5;' and 'int x ={5};' are the same thingFiat
why do you tag C++ here?Uroscopy
@Uroscopy the question asks if it is valid for c++Rockbound
A
13

This

&(ULONG){ HEAP_COMPATIBILITY_LFH },

is not a casting. It is a compound literal. It creates an object of the type ULONG with automatic storage duration and initializes it with the value HEAP_COMPATIBILITY_LFH. Then the address of the object is taken.

Here is a demonstrative program.

#include <stdio.h>

int main(void) 
{
    unsigned long *p = &( unsigned long ){ 10ul };
    
    printf( "%lu\n", *p );
    
    return 0;
}

The program output is

10

From the C Standard (6.5.2.5 Compound literals)

3 A postfix expression that consists of a parenthesized type name followed by a brace enclosed list of initializers is a compound literal. It provides an unnamed object whose value is given by the initializer list.

You may imagine the definition of the compound literal the following way.

For example you may initialize a scalar variable using a braced list like

unsigned long x = { 10ul };

But a compound literal has no name. So this construction

( unsigned long ){ 10ul }

in fact looks like

unsigned long unnamed_literal = { 10ul };
     ^                             ^
     |                             | 
( unsigned long )               { 10ul }

Pay attention to that in C++ there is no such a notion as the compound literal.

Aedile answered 6/3, 2021 at 9:36 Comment(2)
Worth mentioning that this is not valid in C++Deploy
oh! I got it! Thank you~Bedesman
T
6

(ULONG){ HEAP_COMPATIBILITY_LFH } in C is object literal initialization.

It essentially creates an anonymous automatic (auto, on the stack) or static (if used in a filescope compound literal) and initializes it.

(TYPE){ InitVal } is essentially equivalent to TYPE __someInternalNameXYZ = { InitVal } /*lifted above the expression where used*/; __someInternalNameXYZ /*use*/ and it differs from casting in serveral ways.

  1. Casting only works on scalars (pointers and numbers), whereas compound literals work with any type
  2. Casting produces rvalues (can't take their address) whereas compound literals are lvalues (can use unary & on them).
  3. Casting is big hammer: it will happily reinterpret pointers as numbers or vice versa whereas compound literal initialization is more gentle as it abides by the stricter rules for initialization/assignment (https://port70.net/~nsz/c/c11/n1570.html#6.5.16.1)
  4. Casting will produce integer constant expression (usable in switch cases, bitfield widths or array sizes) if the casted value was an integer constant to start with but compound literal initialization never does.

Compound literals are a C99 feature. They don't exist in C++ AFAIK.

In C, you can sometimes use compound literal initialization to get the gentler converting effect of C++'s static_cast.

Typewritten answered 6/3, 2021 at 9:50 Comment(1)
Compound literals were introduced by C99. They're certainly a C11 feature :-)Amethist

© 2022 - 2024 — McMap. All rights reserved.