I'm learning processes and in the following code snippet:
/*
* fork10 - Synchronizing with multiple children (wait)
* Reaps children in arbitrary order
* WIFEXITED and WEXITSTATUS to get info about terminated children
*/
void fork10()
{
pid_t pid[N];
int i, child_status;
for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0) {
exit(100+i); /* Child */
}
for (i = 0; i < N; i++) { /* Parent */
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
else
printf("Child %d terminate abnormally\n", wpid);
}
}
when I trace WIFEXITED
function definition this is what I've got:
#define WIFEXITED(x) (_WSTATUS(x) == 0)
#define _WSTATUS(x) (_W_INT(x) & 0177)
#define _W_INT(w) (*(int *)&(w)) /* convert union wait to int */
I have two questions:
0177
instead of 0b1111111
, I've seen it many times, what's the benefits of using octal number over other formats? Personally I find binary more intuitive.(*(int *)&(w))
? Thanks!
Binary constants such as 0b1111111
are not defined by the C standard and were introduced as an extension by some C implementations somewhat late, so earlier code necessarily used octal and hexadecimal constants, and programmers became accustomed to them. Additionally, octal is more compact, and I can count the number of set bits in 0177
more easily than in 0b1111111
. One quickly becomes accustomed to knowing that 7
means three bits set.
In (*(int *)&(w))
, &(w)
takes the address of the object designated by w
. Then (int *)
converts that address from the type “pointer to type of w” to “pointer to int”. Then *
dereferences that pointer, nominally producing an int
value.
The intent is to access the first bytes of w
as if they were an int
, effectively getting the raw bits that are in w
instead of interpreting it as a structure or whatever other type it is. This is called aliasing .
Aliasing in this way is not supported by the C standard, but many C implementations allow it, and the code you show appear to have been written specifically for such an implementation.
A supported way to get the raw bits of an object is to copy bytes individually, as with:
int b;
memcpy(&b, &w, sizeof b);
Although this looks like a function call, good compilers recognize it as a request to access the first bytes of w
as if they were an int
and optimize it. The result may be a single load instruction. However, wrapping this into a macro that produces the int
as a value involves some complications, which I will leave for further discussion elsewhere. (You can ask a new question about that, if desired.)
1 Why use mask 0177 instead of 0b1111111 ... ?
(This answer only addresses this portion of your question)
Because 0b1111111
is not a C integer constant per 6.4.4.1 Integer constants :
Syntax
1
integer-constant: decimal-constant integer-suffixopt octal-constant integer-suffixopt hexadecimal-constant integer-suffixopt decimal-constant: nonzero-digit decimal-constant digit octal-constant: 0 octal-constant octal-digit hexadecimal-constant: hexadecimal-prefix hexadecimal-digit hexadecimal-constant hexadecimal-digit hexadecimal-prefix: one of 0x 0X nonzero-digit: one of 1 2 3 4 5 6 7 8 9 octal-digit: one of 0 1 2 3 4 5 6 7 hexadecimal-digit: one of 0 1 2 3 4 5 6 7 8 9 abcdef ABCDEF integer-suffix: unsigned-suffix long-suffixopt unsigned-suffix long-long-suffix long-suffix unsigned-suffixopt long-long-suffix unsigned-suffixopt unsigned-suffix: one of u U long-suffix: one of l L long-long-suffix: one of ll LL
Description
2 An integer constant begins with a digit, but has no period or exponent part. It may have a prefix that specifies its base and a suffix that specifies its type.
3 A decimal constant begins with a nonzero digit and consists of a sequence of decimal digits. An octal constant consists of the prefix 0 optionally followed by a sequence of the digits 0 through 7 only. A hexadecimal constant consists of the prefix 0x or 0X followed by a sequence of the decimal digits and the letters a (or A) through f (or F) with values 10 through 15 respectively.
By standard, C only supports decimal, octal, and hexadecimal integer constants.
About your first question: Binary literals are not officially part of the C standard (and are only part of C++ since C++14), hence using octal literals instead of using them can improve portability.
About your second question: &w
takes the address of w
, which is then converted to a pointer to an int ( (int*)&w
) which is dereferenced. What that effectively does is read memory from w
as though w
were an int
.
you should check this link it will help you to solve any question by using (Clockwise/Spiral Rule)
( (int )&(w)) firstly &w means address of w where & is address operator then (int *) means creating pointer to integer so ( till this step you have pointer which point to address of w) finally * before this pointer means (you accessed the value of w )
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.