Is the following code conformat to ANSI C?
typedef struct {
int a;
int b;
} doomdata;
int main(void)
{
int x;
x = (int)&((doomdat a*)0)->b;
printf("x=%d\n" , x);
return x;
}
The part,
(int)&((doomdat a*)0)->b;
is it conformant to ANSI C? What is it supposed to do?
Thanks for any tips.
Napi
-- http://www.axiomsol.com http://www.cs.indiana.edu/hyplan/napi.html
Nov 14 '05
60 2965
"Malcolm" <ma*****@55bank .freeserve.co.u k> wrote in message
news:co******** **@newsg3.svr.p ol.co.uk... "Christian Bau" <ch***********@ cbau.freeserve. co.uk> wrote In C99, there seems to be an actual requirement that casting an integer zero to a pointer type will produce a null pointer. If null pointers don't have all bits zero, and an integer 0 has all bits zero, and converting an integer 0 to a pointer produces a null pointer, then logic says that this conversion cannot leave the bits unchanged.
But in this case we are not casting an integer 0 to a pointer, but a null pointer to an integer.
No, you're not.
You casting integer 0 into a null pointer, offsetting
that pointer by the distance to the member field, then
taking the address of that field (which converts the
pointer back to an integer -- that reverses whatever
happened in converting the integer to a pointer). That
leaves a simple integer constant that can be resolved
at compile time.
The & cancels out the ->. There is no load of a pointer
into an address register whatsoever and no runtime
dereference.
"Malcolm" <ma*****@55bank .freeserve.co.u k> wrote: "Jack Klein" <ja*******@spam cop.net> wrote
When will people get it through their heads that it makes not a whit of difference whether all bits zero happens to be a representation of a null pointer on a particular platform?
Also consider if a null pointer is cast to an integral type, or if a pointer derived by adding an offset to the null pointer is cast to an integer. This cast is a simple bitwise conversion, so results will differ on a platform on which NULL is not all bits zero.
Actually the cast is implementation-defined (and the implementation
can define it to be UB in some, or all, cases).
It would make sense for an implementation to give 0 for
(int)(void *)0, even if (void *)0 were not all bits zero.
The expression (int)&((doomdat a*)0)->b is relying on 2 non-standard
things:
- the compiler doesn't actually dereference 0
- the cast to int works as if pointers are ints in a flat
memory model and (int)NULL == 0
It's irrelevant to this expression whether NULL is all-bits-zero
or not.
"Jack Klein" <ja*******@spam cop.net> wrote in message
news:bn******** *************** *********@4ax.c om... On 28 Nov 2004 20:29:37 GMT, "S.Tobias" <si***@FamOuS.B edBuG.pAlS.INVA LID> wrote in comp.lang.c:
Jack Klein <ja*******@spam cop.net> wrote: On 28 Nov 2004 10:41:21 GMT, "S.Tobias" <si***@FamOuS.B edBuG.pAlS.INVA LID> wrote in comp.lang.c: > Mohd Hanafiah Abdullah <na**@cs.indian a.edu> wrote: > > typedef struct { > > int a; > > int b; > > } doomdata;
> Would this be correct? > (int)&((doomdat a*)0)->a;
Technically it is still undefined behavior, as the semantics of the expression dereference a null pointer.
(This deserves a separate thread, but since I asked the above question here, I'll continue here too.)
As I understand the expression constitutes an access to the structure member.
1. Does a member access constitute an access to the *whole* structure? eg.:
The term 'access' is really only used in the C standard in conjunction with the volatile qualifier, where the wording is unfortunately vague enough that it can be construed several different ways.
struct A { int i; int _i; }; struct B { int i; float f; }; struct A a = {0}; struct B *pb = (struct B*)&a; pb->i; //UB? (*pb).i; //UB?
The two statements above actually have defined behavior, but not for the reason you might think. The language guarantees that a pointer to structure, suitably cast, is also a pointer to its first member. So in given that 'pb' holds any of the following:
- a pointer to any structure type whose first member is an int
- a pointer to an array of ints
- a pointer to a single int
...and the int pointed to has a valid value, the expressions, though not recommended, will work as designed. The compiler must generate code equivalent to *(int *)pb, and if there is actually an int there all is well.
Do I access the first int sub-object in `a' only, or do I access the whole object `a'?
Now that depends what you mean by access. Let's assume a Pentium (1/2/3/4) platform with a typical compiler, which means the size of either of your structures is 8 8-bit bytes. Now let's also assume that this implementation allocates all structures on an address evenly divisible by 8, a not uncommon performance feature of such implementations .
With the assumptions above, if the processor needs to access the structure from memory it will perform a 64-bit access physically, so even though your code does not direct the abstract machine to touch the value of other members in any way, the entire memory space holding the structure will be physically read.
2. I see certain similarity between structs and arrays (in fact, both are called "aggregates "). Why is it that for array: &a[5]; doesn't constitute object access (6.5.3.2#3), whereas for struct: &s.m; &ps->m; the expressions do constitute access? Why is the language designed like this?
There are actually more differences than similarities between structs and arrays, despite the fact that both are aggregates. Structs are first class objects, meaning they can be assigned, passed to and returned from functions by value, and their names are never implicitly converted to pointers. Arrays are not first class objects and do not share any of the characteristics above.
As for other differences in this particular case, this is spelled out by paragraph 3 of 6.5.3.2 of C99:
[begin quotation] The unary & operator returns the address of its operand. If the operand has type ''type'', the result has type ''pointer to type''. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator. Otherwise, the result is a pointer to the object or function designated by its operand. [end quotation]
Note the differences between applying '&' to the result of a '*' operator and to the result of a '[]' operator. In the former case, neither '&' nor '*' are evaluated as such, but note "the constraints on the operators still apply".
Now let's back up to paragraph 1 of 6.5.3.2, which lists the constraints for the unary '&' operator:
[begin quotation] The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier. [end quotation]
Notice that the expression under discussion,
(int)&((doomdat a*)0)->a;
...is none of these things. Specifically, the operand of the '&' operator, '((doomdata*)0)->a' is:
- not a function designator
- not the result of a [] operator
- not the result of a unary * operator
Yes it is unary *. a->b is an alias for (*a).b
- and, because of the null pointer, not an lvalue
Finally consider one last thing, namely that regardless of whether there is an actual access to an object, the expression explicitly performs pointer arithmetic on a null pointer, and such use of a null pointer is undefined in and of itself.
Therefore, & cancels out the -> to yield a simple
integer constant that is resolved at compile time.
In article <q1************ *****@newsread3 .news.pas.earth link.net>
xarax <xa***@email.co m> wrote: ... the compiler will not generate a load into an address register, because the & cancels out the ->. The compiler has all the information it needs to resolve the expression to a constant offset value.
There is only one problem: the compiler really sucks. It does
only what it is absolutely forced to by the C Standard. The C
Standard *allows* it to follow the pointer first, and only then
compute the offset, so it does.
(Well, which "the" compiler are *you* talking about?)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
"Chris Torek" <no****@torek.n et> wrote in message
news:co******** *@news2.newsguy .com... In article <q1************ *****@newsread3 .news.pas.earth link.net> xarax <xa***@email.co m> wrote:... the compiler will not generate a load into an address register, because the & cancels out the ->. The compiler has all the information it needs to resolve the expression to a constant offset value.
There is only one problem: the compiler really sucks. It does only what it is absolutely forced to by the C Standard. The C Standard *allows* it to follow the pointer first, and only then compute the offset, so it does.
Following the pointer into memory would make it
impossible to determine the address of the field.
The & cancels out the apparent dereference.
>> In article <q1************ *****@newsread3 .news.pas.earth link.net> xarax <xa***@email.co m> wrote: >... the compiler will not generate a load into an address register, >because the & cancels out the ->. The compiler has all the information >it needs to resolve the expression to a constant offset value.
"Chris Torek" <no****@torek.n et> wrote in message news:co******* **@news2.newsgu y.com... There is only one problem: the compiler really sucks. It does only what it is absolutely forced to by the C Standard. The C Standard *allows* it to follow the pointer first, and only then compute the offset, so it does.
In article <PU************ *****@newsread3 .news.pas.earth link.net>
xarax <xa***@email.co m> wrote:Following the pointer into memory would make it impossible to determine the address of the field.
Yes. This is why the compiler throws the result away after following
the pointer.
The & cancels out the apparent dereference.
No, the "&" makes the compiler throw away the result of the dereference.
Unfortunately, by then it is too late.
I did say this compiler really sucks. But it conforms.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
"Chris Torek" <no****@torek.n et> wrote in message
news:co******** *@news2.newsguy .com... In article <q1************ *****@newsread3 .news.pas.earth link.net> xarax <xa***@email.co m> wrote: >... the compiler will not generate a load into an address register, >because the & cancels out the ->. The compiler has all the information >it needs to resolve the expression to a constant offset value.
"Chris Torek" <no****@torek.n et> wrote in message news:co******* **@news2.newsgu y.com... There is only one problem: the compiler really sucks. It does only what it is absolutely forced to by the C Standard. The C Standard *allows* it to follow the pointer first, and only then compute the offset, so it does.
In article <PU************ *****@newsread3 .news.pas.earth link.net> xarax <xa***@email.co m> wrote:Following the pointer into memory would make it impossible to determine the address of the field.
Yes. This is why the compiler throws the result away after following the pointer.
The & cancels out the apparent dereference.
No, the "&" makes the compiler throw away the result of the dereference.
Unfortunately, by then it is too late.
I did say this compiler really sucks. But it conforms.
Totally ridiculous.
"xarax" <xa***@email.co m> wrote: "Malcolm" <ma*****@55bank .freeserve.co.u k> wrote: "Christian Bau" <ch***********@ cbau.freeserve. co.uk> wrote: In C99, there seems to be an actual requirement that casting an integer zero to a pointer type will produce a null pointer. If null pointers don't have all bits zero, and an integer 0 has all bits zero, and converting an integer 0 to a pointer produces a null pointer, then logic says that this conversion cannot leave the bits unchanged. But in this case we are not casting an integer 0 to a pointer, but a null pointer to an integer.
No, you're not.
You casting integer 0 into a null pointer,
Casting 0 to a pointer must give a null pointer.
offsetting that pointer by the distance to the member field, then taking the address of that field (which converts the pointer back to an integer
That conversion is implementation-defined
-- that reverses whatever happened in converting the integer to a pointer).
There is no requirement for that to be true. In fact
it can't be true, if there is not an exact mapping
from integers to pointers (eg. segmented architecture,
IA64, etc.)
If you're still not convinced, imagine that NULL
lives at address 0xDEADBEEF. Then &((foo *)0)->bar
might be 0xDEADC00C, for example, and when that's
converted back to an integer you might get 0xDEADC00C
still. Not a very accurate struct offset.
Furthermore, if that is outside the range of signed int
(likely on a 32-bit system) you get undefined behaviour
(again).
That leaves a simple integer constant that can be resolved at compile time.
There is no load of a pointer into an address register whatsoever and no runtime dereference.
For your compiler on Tuesdays, perhaps. There is nothing
(except possible sales figures..) to stop a compiler from
loading 0 to an address register and then incrementing
it, causing a hardware exception.
In article <f3************ *************** *****@4ax.com>,
Jack Klein <ja*******@spam cop.net> wrote: On Sun, 28 Nov 2004 22:17:21 +0000, Christian Bau <ch***********@ cbau.freeserve. co.uk> wrote in comp.lang.c:
In article <co**********@n ews7.svr.pol.co .uk>, "Malcolm" <ma*****@55bank .freeserve.co.u k> wrote:
Also consider if a null pointer is cast to an integral type, or if a pointer derived by adding an offset to the null pointer is cast to an integer. This cast is a simple bitwise conversion, so results will differ on a platform on which NULL is not all bits zero. Not quite; a conversion from a pointer type to an integer does whatever the implementation thinks is a good idea; usually the bits of the representation are copied unchanged, but that is not necessarily so.
In C99, there seems to be an actual requirement that casting an integer zero to a pointer type will produce a null pointer. If null pointers don't have all bits zero, and an integer 0 has all bits zero, and converting an integer 0 to a pointer produces a null pointer, then logic says that this conversion cannot leave the bits unchanged.
I am unsure of your meaning here. Do you mean an integral constant at the source level, as in:
double *dp = (double * 0);
(double *) 0; ...or do you actually mean the value of an integer object, as in:
int x = 0; double *dp = (double *x);
Both.
If you mean the latter, I have never noticed anything in C99 requiring the result be a null pointer.
Could you please clarify and include chapter & verse?
Not directly. The result of conversion from int to for example double*
is defined directly in one special case: When the int is a null pointer
constant, that is the value is 0, and it is an integer constant
expression. But since the result of a conversion only depends on the
value converted and nothing else, the result of converting _any_ int of
value 0 must always be the same. As it is a null pointer in some cases,
it must be a null pointer in all cases.
Christian Bau <ch***********@ cbau.freeserve. co.uk> wrote: The result of conversion from int to for example double* is defined directly in one special case: When the int is a null pointer constant, that is the value is 0, and it is an integer constant expression.
No, the value is not important here, you're misquoting the Standard.
The Standard says: "integer constant expression with the value 0",
so first you look up what is an integer constant expression, and
then you filter only those that have the value zero. Examples are:
0
0x0
0u
(1-1)
'\000'
(int)0.0
7/11
sizeof 13 - sizeof (int)
But since the result of a conversion only depends on the value converted and nothing else, the result of converting _any_ int of value 0 must always be the same. As it is a null pointer in some cases, it must be a null pointer in all cases.
The Std does not say such a thing. If it wanted the value 0 to be
converted into a null pointer, it would say "integer expression with
the value 0" or just "integer value 0". Integer constant expression
is a special case that a compiler must recognize at compile-time.
Conversions between pointer and integer types are explicitly
implementation defined.
--
Stan Tobias
mailx `echo si***@FamOuS.Be dBuG.pAlS.INVALID | sed s/[[:upper:]]//g` This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: James Harris |
last post by:
Having updated my Debian system it now complains that I am using
an incompatible pointer type in warnings such as "passing arg 2
of 'bind' from incompatible pointer type" from code,
struct sockaddr_in sockad1;
....
retval = bind (sock1, &sockad1, sockad1len);
I can coerce the pointer with
|
by: jimjim |
last post by:
Hello,
Any help will be much appreciatted. My problem is as follows:
I declare as global variables:
typedef struct _Node{ ..; ..;}Node;
Node *Graph;
in a function called initiallise(), I allocate memory and copy information:
for(i )
|
by: Peter Dunker |
last post by:
Hi,
I will write ANSI C89.
Is the following struct defenition correct ?
I wrote it with VC6(Windows IDE) and at first no Problem.
As I changed a compiler switch to 'no language extension',
the compiler said that the union has no name.
Is it right that in ANSI C the union must be named inside this kind of
structure ?
|
by: PCHOME |
last post by:
Hello! I am working on dividing a single C file into several files.
Now I encounter a problem about the global variables
and can not find a way to solve it.
All global variables and codes used to be in that single file, that
worked OK. But when I divdie that file into several ones, I
have many "invalid use of undefined type" errors.
The four files are main.c, main.h, readLP.h, and readLP.c.
In readLP.h
|
by: lp-boy |
last post by:
Hello!
Is the following code legal?
template<class T>
struct holder{};
struct A
{
holder<struct B*> h; //!!!
| |
by: werasm |
last post by:
Hi all,
What is the difference between:
typedef struct
{
...
} MyS1;
....and...
|
by: Bill |
last post by:
Hello All,
I am trying to pass a struct to a function. How would that best be
accomplished?
Thanks,
Bill
|
by: beet |
last post by:
Hi all,
I tried to declare a c++ struct like following in a header file; I
want to include
this header file in other files to create and access this struct.
------
1 #ifndef _SEARCHDATA_H_
2 #define _SEARCHDATA_H_
3
|
by: BIll Cunningham |
last post by:
pg 128 of kandr2 speaks of a struct
struct point{
int x;
int y;
};
I understand this but what is it saying about using intialize variables like
such.
|
by: Lew Pitcher |
last post by:
(having trouble getting my reply through - hopefully, third time is a charm)
On November 11, 2008 19:53, in comp.lang.c, BIll Cunningham
(nospam@nspam.invalid) wrote:
Why an int? Because K&R chose to use an int.
Why not a double? Because K&R chose to use an int.
Note the phrase "syntactically analogous". It means that the /syntax/ of
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look !
Part I. Meaning of...
| |
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed.
This is as boiled down as I can make it.
Here is my compilation command:
g++-12 -std=c++20 -Wnarrowing bit_field.cpp
Here is the code in...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth.
The Art of Business Website Design
Your website is...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own....
Now, this would greatly impact the work of software developers. The idea...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols.
I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
|
by: bsmnconsultancy |
last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...
| |