Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 
like image 303
Adam Avatar asked Dec 01 '22 13:12

Adam


2 Answers

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.

like image 137
Vlad from Moscow Avatar answered Dec 05 '22 07:12

Vlad from Moscow


(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.

like image 20
PSkocik Avatar answered Dec 05 '22 07:12

PSkocik