I've noticed in some source code the line:
if(pthread_create((pthread_t[]){}, 0, start_thread, pthread_args)) {
...
It works correctly, but how to understand the first argument?
It seems, that curly braces converts to pthread_t[] type.
P.s. I googled, but didn't find answer, only some guesses (some form of initialization, or legacy feature of c?)
This is a compound literal, with a constraint violation since initializer braces cannot be empty:
(pthread_t[]){}
Using gcc -std=c99 -Wall -Wextra -Wpedantic this produces the warning:
compound_literal_pthread.c:6:36: warning: ISO C forbids empty initializer braces [-Wpedantic]
pthread_t *ptr = (pthread_t []){};
The result seems to be a pointer to pthread_t, though I don't see this behavior documented in the gcc manual. Note that empty braces are allowed as initializers in C++, where they are equivalent to { 0 }. This behavior seems to be supported for C, but undocumented, by gcc. I suspect that is what is happening here, making the above expression equivalent to:
(pthread_t[]){ 0 }
On my system, pthread_t is a typedef for unsigned long, so this expression would create an array of pthread_t containing only a 0 element. This array would decay to a pointer to pthread_t in the function call.
It's a compound literal as mentioned by #some-programmer-dude.
In this specific case it is use to create an array to store the thread_id and discharge it later without the need of creating an extra variable. That is necessary because pthread_create does not accept NULL as argument for thread_id.
You're creating an array with pthread[]. You can pass values in the curly braces if you define a length for the argument.
What you're dealing with there is an array initializer, which happens to be the empty array. You'd usually find it as:
int my_array[] = (int[]){10, 20, 30};
And it would initialize my_array to contain three elements. Here there are no elements, hence the awkward syntax.
Related
Why do GCC and Clang produce different output with this conforming C code:
int (puts) (); int (main) (main, puts) int main;
char *puts[(&puts) (&main["\0April 1"])]; <%%>
Neither compiler produces any warning or error even with -Wall -std=c18 -pedantic, but the program produces no output when built with GCC but prints the current date when built with Clang.
Why do GCC and Clang produce different output with this conforming C
code:
int (puts) (); int (main) (main, puts) int main;
char *puts[(&puts) (&main["\0April 1"])]; <%%>
In the first place, it is conforming code, though it does make use of a variable-length array, which is an optional language feature in C11 and C17. Some of the obfuscations are
use of the obscure digraphs <% and %>, which mean the same thing as { and }, respectively.
parenthesizing the function identifiers in function declarations
a forward declaration of function puts that is not a prototype
a K&R-style definition of function main
with a VLA parameter
whose dimension expression contains a function call
and a reference to another parameter
use of unconventional identifiers for the parameters to function main()
use of identifiers (puts and main) in declarations of an object and a function, respectively, with the same identifier
use of the identifier main for something more than the program's entry-point function
inversion of the conventional order of the operands of the indexing operator ([])
plus, indexing a sting literal
calling a function via an explicit function pointer constant expression
A string literal with an explicit null character within
Unconventional placement (and omission) of line breaks
A less obfuscated equivalent would be
int puts();
int main(
int argc,
char *argv[ puts("\0April 1" + argc) ]
) {
}
But the central question about the difference in behavior between the version compiled with GCC and the one built with Clang comes down to whether the expression for the size of the VLA function parameter is evaluated at runtime.
The language spec says that when a function parameter is declared with array type, its type is "adjusted" to the corresponding pointer type. That applies equally to complete, incomplete, and variable-length array types, but the spec does not explicitly say that the expression(s) for the dimension(s) are not evaluated. It does specify that expressions go unevaluated in certain other cases, and it even makes an exception to such a rule in the case of sizeof expressions involving VLAs, so the omission in this case could be interpreted as meaningful.
That makes a difference only for parameters of VLA type, because only for those can evaluation of the dimension expression(s) produce side effects on the machine state, including, but not limited to, observable program behavior.
GCC does not evaluate the VLA parameter's size expression at runtime, and I am inclined to take this as conforming to the intent of the standard. As a result, the GCC-compiled program does nothing but exit with status 0.
Clang does evaluate the VLA parameter's size expression at runtime. Although I disfavor this interpretation of the spec, I cannot rule it out. When it does evaluate the size expression, it uses the passed value of the first parameter. When the program is run without arguments, then the first parameter has value 1, with the result that the standard library's puts function is called with a pointer to the 'A' in "\0April 1".
int (puts) ();
int (main) (main, puts)
int main;
char *puts[(&puts) (&main["\0April 1"])];
{
}
Somebody's got a compiler bug; I'm just not sure who anymore. I don't understand why any compiler would emit code to evaluate the size parameter of a VLA as an argument.
The clang output is rather bizarre. For it to work, it would have had to find main in the function's scope but puts in the global scope despite having already encountered the declaration for puts. Normally, you can access a variable in its own declaration.
If somebody did this in production code my answer would be rather: "Stop using K&R function definitions."
If I do:
int j = ({int x = 7; x+3;});
In i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) gcc it compiles just fine. The block in question ({int x = 7; x+3;}) returns the value of the last statement as the value of the block. If you remove the parenthesis it doesn't compile. Can I expect this to work in most C compilers?
Additionally, what is the name for this construct? I have had a lot of trouble searching for it because search engines don't index () or {} and C is a terrible search term. I also haven't been able to find anything about it in any of my books, probably because I don't know what to look for.
It's a GCC extension:
A compound statement enclosed in parentheses may appear as an expression in GNU C. This allows you to use loops, switches, and local variables within an expression.
Recall that a compound statement is a sequence of statements surrounded by braces; in this construct, parentheses go around the braces. For example:
({ int y = foo (); int z;
if (y > 0) z = y;
else z = - y;
z; })
is a valid (though slightly more complex than necessary) expression for the absolute value of foo ().
The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)...
If you remove the parenthesis it doesn't compile.
Without the parentheses, the compiler will treat this as an aggregate initialization block and will fail when it sees the int keyword. You cannot have keywords in initializer blocks.
6.7.8 Initialization
11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The
initial value of the object is that of the expression (after conversion); the same type
constraints and conversions as for simple assignment apply, taking the type of the scalar
to be the unqualified version of its declared type.
6.2.5 Types
21 Arithmetic types and pointer types are collectively called scalar types. Array and
structure types are collectively called aggregate types.
Can I expect this to work in most c compilers?
No. Looks like a non-standard GNU extension.
Additionally, what is the name for this construct?
I wonder if there is any. Actually, this is similar to what macros typically do.
You can expect it to work in most versions of GCC.
You can expect it to work almost nowhere else - it is a GCC extension.
The section of the GCC manual that describes the feature is titled 'Statements and Declarations in Expressions':
A compound statement enclosed in parentheses may appear as an expression in GNU C.
Later it says:
Any temporaries created within a statement within a statement expression will be destroyed
at the statement’s end. This makes statement expressions inside macros slightly
different from function calls.
So, 'statement expression' seems to be the name used in the documentation.
This is my code:
#include <stdio.h>
typedef struct {
const char *description;
float value;
int age;
} swag;
typedef struct {
swag *swag;
const char *sequence;
} combination;
typedef struct {
combination numbers;
const char *make;
} safe;
int main(void)
{
swag gold = { "GOLD!", 100000.0 };
combination numbers = { &gold, "6503" };
safe s = { numbers, "RAMCON" };
printf("Contents = %s\n", s.numbers.swag->description);
getchar();
return 0;
}
Whenever I compile it with the VS developer console, I get this error: error C2440: 'initializing' : cannot convert from 'combination' to 'swag *'.
However if I use gcc the console just prints: "GOLD!". Don't understand what's going on here.
What you stumbled upon is an implementation-specific variant of a popular non-standard compiler extension used in various C89/90 compilers.
The strict rules of classic C89/90 prohibited the use of non-constant objects in {} initializers. This immediately meant that it was impossible to specify an entire struct object between the {} in the initializer, since that would violate the above requirement. Under that rule you could only use scalar constants between the {}.
However, many C89/90 compilers ignored that standard requirement and allowed users to specify non-constant values when writing {} initializers for local objects. Unfortunately, this immediately created an ambiguity if user specified a complex struct object inside the {} initializer, as in your
safe s = { numbers, "RAMCON" };
The language standard did not allow this, for which reason it was not clear what this numbers initializer should apply to. There are two ways to interpret this:
The existing rules of the language said that the compiler must automatically enter each level of struct nesting and apply sequential initializers from the {} to all sequential scalar fields found in that way (actually, it is a bit more complicated, but that's the general idea).
This is exactly what your compiler did. It took the first initializer numbers, it found the first scalar field s.numbers.swag and attempted to apply the former to the latter. This expectedly produced the error you observed.
Other compiler took a more elaborate approach to that extension. When the compiler saw that the next initializer from the {} list had the same type as the target field on the left-hand side, it did not "open" the target field and did not enter the next level of nesting, but rather used the whole initializer value to initialize the whole target field.
This latter behavior is what you expected in your example (and, if I am not mistaken, this is the behavior required by C99), but your C89/90 compiler behaved in accordance with the first approach.
In other words, when you are writing C89/90 code, it is generally OK to use that non-standard extension when you specify non-constant objects in local {} initializers. But it is a good idea to avoid using struct objects in such initializers and stick to scalar initializers only.
Looks like an issue with the initializers. If you use the proper options with gcc, it will tell you this:
$ gcc -Wall -ansi -pedantic x.c
x.c: In function ‘main’:
x.c:21: warning: initializer element is not computable at load time
x.c:22: warning: initializer element is not computable at load time
which is propably the same issue VS is trying to tell you. You can make these go away if you declare gold and numbers static.
I am fairly new to C and I don't understand why the following two statements do not create the same result:
char *fields[14] = {NULL};
const int num_fields = 14;
char *fields[num_fields] = {NULL};
Option 1 works, but option 2 does not. It says "variable-sized object may not be initialized" and it gives a warning "warning: excess elements in array initializer". I use gcc 4.2.1 on OSX.
Thanks for sharing your thoughts!
The second object is called a VLA (Variable Length Array), well defined by C99. To achieve what you want you can use this:
for (i = 0; i < num_fields; i++)
fields[i] = NULL;
The gist of the issue is that const int num_fields is very different from 14, it's not a constant, it's read-only.
Even if you define num_fields with const keyword, compiler interprets it as variable only. you can have alternative for this by defining following macro:
#define num_fields 14
char *fields[num_fields] = {NULL};
Although num_fields has a const qualifier, it is still considered a variable by the compiler.
Therefore, you are attempting to declare a variable-sized array, and initialisers (the {NULL} part) cannot be used in conjunction with them.
Your construction works in C++, where a const int will be treated as a compile-time constant ("constant expression"), and hence available for use as a compile-time array size.
(This aspect was one of B. Stroustrup's design goals for C++, to eliminate the need for compile-time macros if possible)
However in C, your definition of "num_fields" effectively declares a read-only memory location with your preset value, and hence is not under C rules a "constant expression" valid at compile time, and hence may not be used as an array size at the outermost 'program' scope.
I'm trying to initialize an array of structures to all-0's, using the below syntax:
STRUCTA array[MAX] = {0};
However, I'm getting the following warning from gcc :
warning: missing braces around initializer
What am i doing wrong - is there another/better way to do this ?
It the first member of your struct has a scalar type, use
STRUCTA array[MAX] = {{ 0 }};
If the first member of your struct happens to be another struct object, whose first member has scalar type, then you'll have to use
STRUCTA array[MAX] = {{{ 0 }}};
and so on. Basically, you have to open a new level of nested {} every time you "enter" another nested aggregate (a struct or an array). So in this case as long as the first member of each nested aggregate is also an aggregate, you need to go deeper with {}.
All these extra braces are only there to avoid the warning. Of course, this is just a harmless warning (in this specific case). You can use a simple { 0 } and it will work.
Probably the the best way to deal with this is to disable this warning entirely (see #pmg's answer for the right command-line option). Someone working on GCC wasn't thinking clearly. I mean, I understand the value of that warning (and it can indeed be very useful), but breaking the functionality of { 0 } is unacceptable. { 0 } should have been given special treatment.
gcc is being a nuisance. It should accept that without warnings.
Try this
STRUCTA array[MAX] = {{0}};
That gcc behaviour can be controlled with the option -Wmissing-braces or -Wno-missing-braces.
-Wall enables this warning; to have -Wall but not the missing braces, use -Wall -Wno-missing-braces
This is merely a harmful warning issued by gcc, and I would disable it with -Wno-braces. {0} is an extremely useful "universal zero initializer" for types whose definition your code is not supposed to be aware of, and gcc's discouraging its use is actively harmful to the pursuit of good code.
If gcc wants to keep this warning, it should at least special-case {0} and disable the warning in this one case.
You can avoid the warning by using completely empty braces:
STRUCTA array[10] = {};
The array will be aggregate-initialized, which means that each of the structs in it will in turn be value-initialized. Value-initialization with empty brackets turns into aggregate-initializion of each struct, which sets all fields to 0, which is what you want.
This works in all cases as long as your structs are POD (see the links above for precise description).
Arrays are initialized with braces, but so are structs. You probably need to put an extra set of braces around your 0 and, depending on how STRUCTA is defined, some extra 0s separated by commas.
It depends on the STRUCTA. For example :
typedef struct structa
{
int a, b;
} STRUCTA;
int main (int argc, char const* argv[])
{
STRUCTA array[10] = {{0,0}};
return 0;
}
Can STRUCTA be assigned to 0?
You can always use memset(), too.