In clang, a pointer to a function and the designation/designator have distinct resulting grouping symbols, parenthesis compared to curly braces as seen in the code fragments further down.
What is:
type * type(*)(type)
used for and versus/what is:
type *(type)
used for? Curly braces are for use in lists, compound statements and aggregates while parenthesis are primarily used for ordering, grouping, casting and arguments.
It looks like the first is a type reference to a function pointer accepting a specific type argument which, if enclosed in parenthesis either orders the group be evaluated individually if part of a larger expression or creates a cast which after the resolution of the function would convert it to a specific value of the return type of the specified size and alignment requirements instead of the binary sequence containing the value.
The second one is in a block with curly braces and thus a compound object or statement block since I can't see how it would be attached to an aggregate though it may be reference to a function body result of a call.
The second snippet looks like a type reference to a type defined or object group and, since a type may not share a name with an object, effectively making it a keyword, I presume that this somehow creates a named object that is multiplied with itself, or is a reverse cast or something since keywords with an asterisk have no real use aside from object declarations.
P
Why does the initial have parenthesis enclosing the symbol whereas the second symbol uses curly braces?
For example, the following code fragment when compiled,
.
(*function)(1);
mentions the symbol in the comments after compiling is noted as:
(type *(*)(type))
with parenthesis encompassing the representation in the compilation log of the console.
.
whereas:
.
function(1);
mentions the symbol in the comments after compiling is noted as:
{type *(type)}
with curly braces encompassing the representation in the compilation log of the console.
.
What is the distinction between the two for, and under what circumstances is it practically applied in any usual/useful contexts?
My general observations of the syntax and semantics of the C language suggest to me the first appears to be a basic ordered-group expression which may be used in a comma-separated list or as a function parameter whereas the second appears to be a struct, union or block statement.
I was exploring function pointers and so I tried both and those two notes were clang's comments of the compilation. None of the other 5 posts I read seemed to clarify the nature of the grouping symbols in any context but did provided additional insight to function pointers and their applications.
Thank you!
function designator is an expression with function type.
for example in
a = foo(x);
foo is a function designator.
Function pointer is a reference to the function. Function designators decay to function pointers when used as values.
int (*fptr)(int) = foo;
Related
I tried to solve exercise 1-24 in K&R C book in which you have to create a program which can detect basic syntax errors (unbalanced parentheses, brackets and so on). I ran some tests to debug it on C source files scattered on my system.
My program detected an error when it met this line in a file :
av_opt_set_q (abuffer_ctx, "time_base", (AVRational ){ 1, INPUT_SAMPLERATE }, AV_OPT_SEARCH_CHILDREN);
I made the assumption that, every time a regular curly bracket is encountered (outside comments, double quotes), parentheses and brackets must be balanced. This is not true as this error showed. Unfortunately I cannot find what it means. Thanks for your help.
This
(AVRational ){ 1, INPUT_SAMPLERATE }
is a compound literal. Check more about it here.
From the C11, chapter ยง6.5.2.5
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.
That said, I do not see how the braces are not balanced here. This is a valid syntax and your tool should consider this while making decision.
anyone familiar with this macro definition:
#define CrashData (*((CRASH_DATA *)CRASHDATA_ADDRESS))
where
CRASH_DATA is a typedef struct
CRASHDATA_ADDRESS is 0xF3F80UL
I suspect that we are creating a struct variable called CrashData that is placed from the addrees and forward right?
Thank you for your help, Pointer declaration is kind of confusing.
I suspect that we are creating a struct variable called CrashData that is placed from the addrees and forward right?
No, not exactly.
In the first place, there is no variable anywhere in sight. You spoke correctly when you called the code a macro definition; therefore the code defines a macro named CrashData, which is not at all the same thing as a variable.
So let's look at the macro's replacement text:
(*((CRASH_DATA *)CRASHDATA_ADDRESS))
Starting from the inside, you claimed that CRASHDATA_ADDRESS is 0xF3F80UL, which I interpret to mean that it is actually a macro, with that unsigned long constant as its replacement text.
(CRASH_DATA *) can only be a cast operator, so it is unsurprising to hear that CRASH_DATA is a typedefed type alias, or perhaps a macro expanding to such. The result of the cast is a pointer to CRASH_DATA. It might in particular point to a block of memory at the address specified by CRASHDATA_ADDRESS, but the standard only says
the result is implementation-defined, might not be correctly aligned,
might not point to an entity of the referenced type, and might be a
trap representation.
the result of the cast is enclosed in parentheses and the dereferencing operator (unary *) is applied to it. The result of dereferencing a pointer is an lvalue designating the object to which the pointer points.
the dereferenced result is enclosed in parentheses, which serve their ordinary grouping role. This is useful so that operator precedence does not cause surprising effects where the macro is used.
Overall, then, the intent of the macro seems to be to represent an expression that presents a block of memory starting at CRASHDATA_ADDRESS as if it were an object of type CRASH_DATA. Since CRASH_DATA is a structure type, you would access its members via the . operator:
if (CrashData.member1 == y) {
CrashData.member2 = x;
}
Although you might write similar code if CrashData were a variable, it is not a variable, and there are ways in which it would behave differently than a variable.
First, ((CRASH_DATA *)(CRASHDATA_ADDRESS)) is a typecast, telling the compiler to treat the address defined in CRASHDATA_ADDRESS as if it were a pointer to an item of type CRASH_DATA.
Next the star (*) operator is dereferencing the pointer. Since it is a pointer to a struct, once referenced you can access any of the struct's members via the dot (.) operator.
You should be able to access the data like this:
CrashData.some_struct_member
Anyways, what is important is to understand you are not 'creating' a new struct variable, you are only telling the compiler to treat the data stored at memory address 0xF3F80UL as a variable of type CRASH_DATA.
In this post, the OP contains code where there is a lot wrong with, but 1 line made me especially curios, since I wasn't able to look anything up, disallowing it. This is the specific line:
int n = 100000, arr[n];
Is the order of declaration and initialization beeing ensured?
So here I would assume it might even happen that n wasn't initialized when arr gets declared, what obvisiously would not be good.
But I wasn't able to find any statement regarding this in the iso/iec 9899 draft at hand neither stating it undefined nor defining it.
So is this as I assume not defined behavior?
Or is it?
And either way, what is the rule beeing applyed for that result?5
Edit:
Is that valid for C99, too?
In short: Your code is correct. It is your premise which is wrong. The two declarations are not "in the same sequence point". (As a sidenote: there cannot be anything in a point, but only between two points, points are dimensionless).
The details:
6.8.2 of the standard shows the grammar of a compound statement which is the basis of every function body:
compound-statement:
{ block-item-listopt }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
Relevant here is the block-item. As shown, it can be a statement or a declaration. This implies that a declaration is not a statement. You show a declaration, so the , is not an operator here, but seperates the init-declarators (a declarator optionally with an initialiser, see 6.7 for the grammar). And there is a sequence point right after the declarator (and before the optional initialiser, btw.).
6.7.6p3: A full declarator is a declarator that is not part of another declarator. The end of a full declarator is a sequence point. If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified. Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.
Regarding the "execution order": That is actually left to the implementation. But the standard requires to follow the abstract machine. Sequence points are the fundamental ordering concept.
The question is actually not directly related to VLAs, but declarators in general. Without citing the sections of all previous versions, the behaviour is identical in all version, because otherwise something like int i = 3, k = i; would also not work (it does).
I was digging SnoopSnitch's source code when I found in one of it's libraries this line, written in C :
(_s, m);
_s and m are both structures so what can it be ?
PS: Check the end of this file to see the actual source code.
C hasn't "methods" at all, it has functions.
In any event, the code you present is not a function call, it is an expression statement. The parentheses serve their precedence-overriding grouping function, albeit unnecessarily, and the comma is the comma operator, which evaluates both operands, and has as its result the value of its second operand.
Inasmuch as the result is unused and the comma's operands are simple variable names, the statement overall has no side effects. The only purpose I can think of is the one #chux suggested in comments: to provide a statement where you can insert a breakpoint for debugging, and especially for examining the values at that point of the two variables involved.
This is mainly a followup to Should definition and declaration match?
Question
Is it legal in C to have (for example) int a[10]; in one compilation unit and extern int a[4]; in another one ?
(You can find a working example in my answer to ref'd question)
Disclaimers :
I know it is dangerous and would not do it in production code
I know that if you have both in same compilation unit (typically through inclusion of a .h in the file containing the definition) compilers detects an error
I have already read Jonathan Leffler' excellent answer to How do I use extern to share variables between source files? but could not find the answer to this specific point there - even if Jonathan showed even worse usages ...
Even if different comments in referenced post spotted that as UB, I could not find any authoritative reference for it. So I would say that there is no UB here and that second compilation unit will have access to the beginning of the array, but I would really like a confirmation - or instead a reference about why it is UB
It is undefined behavior.
Section 6.2.7.2 of C99 states:
All declarations that refer to the same object or function shall have
compatible type; otherwise, the behavior is undefined.
NOTE: As mentioned in the comments below, the important part here is [...] that refer to the same object [...], which is further defined in 6.2.2:
In the set of translation units and libraries that constitutes an
entire program, each declaration of a particular identifier with
external linkage denotes the same object or function.
About the type compatibility rules for array types, section 6.7.5.2.4 of C99 clarifies what it means for two array types to be compatible:
For two array types to be compatible, both shall have compatible
element types, and if both size specifiers are present, and are
integer constant expressions, then both size specifiers shall have the
same constant value. If the two array types are used in a context
which requires them to be compatible, it is undefined behavior if the
two size specifiers evaluate to unequal values.
(Emphasis mine)
In the real world, as long as you stick to 1D arrays, it is probably harmless, because there is no bounds checking and the address of the first element remains the same regardless of the size specifier, but note that the sizeof operator will return different values in each source file (opening a wonderful opportunity to write buggy code).
Things start to get really ugly if you decide to extrapolate on this example and declare multidimensional arrays with different dimension sizes, because the offset of each element in the array will not match with the real dimensions any more.
Yes, it is legal. The language allows it.
In your specific case there will be no undefined behavior as the extern declared array is smaller than the actually allocated array.
It can be used in a case where the declaring module uses the "unpublished" array elements for e.g. housekeeping of its algorithms (abstraction hiding).