Hi,
Can somebody please help me grok the offsetof() macro?
I've found an explanation on http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.
The sticking point seems to be:
((s *)0) takes the integer zero and casts it as a pointer to s.
To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?
Thanks.
Simon
--
"Being a social outcast helps you stay concentrated on the really important
things, like thinking and hacking." - Eric S. Raymond
Nov 15 '05
44 3759
Keith Thompson <ks***@mib.or g> writes: Tim Rentsch <tx*@alumnus.ca ltech.edu> writes: Keith Thompson <ks***@mib.or g> writes: [...] My idea (which is totally impractical because it would break existing code) is that the "nil" keyword would be the *only* legal null pointer constant.
Ahh I see. The revised language would not only add 'nil' but also would take away '0' (and '(void*)0') as a way of writing null pointer values. Clearly there are some benefits to using 'nil' as the only form of null pointer constant. What do you think the costs are, not counting the cost of converting existing code so that it uses 'nil'? Or have you thought much about what the costs would be?
I've used other languages that have a keyword that's used as the equivalent of a null pointer constant, and that don't allow any other form of null pointer constant. I'll just mention that programmers in those languages typically don't know or care how null pointers are represented; even if they happen to know how a given implementation represents null pointers, they don't try to make use of the knowledge. And their FAQs don't have to devote an entire section to null pointers.
Sure; certainly there are some benefits to the 'nil' approach.
I don't think there are any costs to this approach, apart from the insurmountable cost of all the existing C code that would be broken.
In my experience these kinds of design choices essentially always
carry ongoing costs as well as benefits. That isn't to say that the
benefits won't outweigh the costs necessarily, only that there also
are costs to consider. So if you aren't aware of any costs besides
the cost of converting existing code, maybe you haven't considered
the ramifications fully enough yet?
To put this another way, when C was being designed, there already were
languages with, eg, NULL to indicate null pointers (and no other forms
allowed). Yet KT and/or DR decided to use 0 for null pointers, so
they must have thought there were some benefits to doing that over
using NULL. If the original C model has some benefits, then giving
those up is a cost.
I'm almost tempted to suggest adding a "nil" keyword to the next C standard, with the obvious semantics, *without* eliminating the other forms of null pointer constant. But providing a better approach without removing the old one would just add to the confusion.
Why not just use NULL? A lint-like tool, or a compiler warning
switch, could be used to flag those cases where a pointer value is
needed yet a null pointer constant other than NULL is used. That
approach seems more likely to get to where you hope to get to.
Tim Rentsch <tx*@alumnus.ca ltech.edu> writes: Keith Thompson <ks***@mib.or g> writes:
[...] I've used other languages that have a keyword that's used as the equivalent of a null pointer constant, and that don't allow any other form of null pointer constant. I'll just mention that programmers in those languages typically don't know or care how null pointers are represented; even if they happen to know how a given implementation represents null pointers, they don't try to make use of the knowledge. And their FAQs don't have to devote an entire section to null pointers.
Sure; certainly there are some benefits to the 'nil' approach.
I don't think there are any costs to this approach, apart from the insurmountable cost of all the existing C code that would be broken.
In my experience these kinds of design choices essentially always carry ongoing costs as well as benefits. That isn't to say that the benefits won't outweigh the costs necessarily, only that there also are costs to consider. So if you aren't aware of any costs besides the cost of converting existing code, maybe you haven't considered the ramifications fully enough yet?
To put this another way, when C was being designed, there already were languages with, eg, NULL to indicate null pointers (and no other forms allowed). Yet KT and/or DR decided to use 0 for null pointers, so they must have thought there were some benefits to doing that over using NULL. If the original C model has some benefits, then giving those up is a cost.
C was based on a couple of earlier languages. BCPL, if I recall
correctly, was a low-level language that treated all of memory as an
array of words; pointers were effectively indices into that array.
Conceivably there might be some advantage (other than historical) in
C's approach rather than defining single keyword for null pointers. I
just can't think of anything. Can you? I'm almost tempted to suggest adding a "nil" keyword to the next C standard, with the obvious semantics, *without* eliminating the other forms of null pointer constant. But providing a better approach without removing the old one would just add to the confusion.
Why not just use NULL? A lint-like tool, or a compiler warning switch, could be used to flag those cases where a pointer value is needed yet a null pointer constant other than NULL is used. That approach seems more likely to get to where you hope to get to.
I have no real hope of getting anywhere with this.
--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Keith Thompson <ks***@mib.or g> writes: Tim Rentsch <tx*@alumnus.ca ltech.edu> writes: Keith Thompson <ks***@mib.or g> writes: [...] C99 6.3.2.3p3 defines the term "null pointer constant":
An integer constant expression with the value 0, or such an expression cast to type void *, is called a _null pointer constant_.
I don't see any permission for the implementation to define null pointer constants that don't meet that definition. 7.17p3 says that the macro NULL "expands to an implementation-defined null pointer constant". This allows the implementation to define NULL as either 0, (void*)0, or ('/'/'/'-'/'/'/'); it doesn't allow it to define NULL as (void*)(char*)0 . 7.17p3 constrains the implementation' s definition of NULL; it doesn't define "null pointer constant".
I agree the issue is not clear cut. I wasn't meaning to start a debate on the issue, only to give a plausible and reasonable alternative reading. However, since you ask, let me frame some arguments.
Actually, we aren't in agreement. I think the issue is (reasonably) clear-cut.
I don't see any inconsistency between saying the issue is reasonably
clear-cut and saying the issue is not clear cut. There's a difference
in degree between the two statements, but they aren't inconsistent.
So I'm not sure that I can agree that we aren't in agreement. :) 1. The Standard isn't always careful in how definitions are given. There was discussion recently on the definition of "definition ", for example. Although I think it would be a good idea if the Standard were more rigorous (and, dare I say it, "mathematic al") in defining and using special terms, that isn't what it does now.
Agreed. However, there are cases where the standard gives explicit permission to do something in an implementation-defined way, such as the declaration of main(). The fact that it doesn't do so here is, IMHO, significant.
Saying you believe it's significant isn't really a very convincing
argument, is it?
More specifically, look at the wording of 5.1.2.2.1, where 'main' is
specified. Clearly paragraph 1 intends to give a precise
specification of 'main'; in particular, the word "shall" is used.
The wording used in 6.3.2.3 p3 is quite different. The analogy
just doesn't seem strong enough to be very convincing. 2. Note the particular wording in 6.3.2.3 p3: such-and-such kind of expression *is called* a null pointer constant. It doesn't say the list is exhaustive. If there are any candidates for definitions in the Standard that are one-way definitions rather than two-way definitions, surely the statement in 6.3.2.3 p3 must be one of them.
Since there's a clear and unambiguous interpretation assuming the definition is exhaustive, I believe that's the best interpretation.
If you want to believe that, it's ok with me. But your statement
doesn't offer me any reason why I should believe it.
Furthermore, there's an obvious reason not to believe it, which is
that interpreted as an exhaustive definition, the given wording is
clearly incomplete since it doesn't cover things like '((void*)0)'.
The standard doesn't give explicit permission for other forms of null pointer constant. Using (void*)42 in a context that requires a null pointer constant is a constraint violation. An implementation that doesn't issue a diagnostic for such a use is non-conforming.
Saying an implementation that doesn't issue a diagnostic for such a
use must be non-conforming is predicated on the assumption that
implementation-defined null pointer constants aren't allowed. It's
circular reasoning.
On the other hand, an implementation certainly is free to choose a
representation for pointers where any address under, say, 100 is to be
interpreted as a null pointer. On such an implementation, it would be
perfectly reasonable for '(void*)42' to be allowed as a null pointer
constant.
Similarly, the standard doesn't give permission for other forms of integer constants. An implementation can accept 0b11001001 as a binary constant as a language extension, but it must issue a diagnostic for any such constant in conforming mode.
Not the same thing at all. The form of integer constants is specified
by syntax rules; these rules have a precise and exact meaning. I
don't have a reference handy, but I believe there is a statement in
the Standard to the effect that a syntax violation must result in a
diagnostic. Certainly using an implementation-defined null pointer
constant *might* result in a diagnostic being issued, but I don't know
of any provision that *requires* one. 3. The mere use of the term "implementa tion-defined null pointer constants" suggests that there are some null pointer constants that are defined by the implementation rather than by the Standard. Otherwise, 7.17 p3 could have said just that "NULL expands to a null pointer constant". Based on the way other parts of the Standard are written, the more concise form seems more likely if an implementation were not allowed to define null pointer constants (perhaps with a footnote that says, eg, "The choice of which null pointer constant expression to use is implementation defined.").
The term "implementa tion-defined" doesn't just mean that the implementation gets to make a choice; it also means it has to document that choice. If the standard merely said that NULL expands to a null pointer constant, an implementation wouldn't be required to document what it actually expands to. This would be no great loss, since code shouldn't depend on the choice, but I believe the intent is that (a) an implementation can choose any valid null pointer constant as the expansion of NULL, and (b) it must document what choice it makes.
That's a plausible interpretation. However, that interpretation seems
better expressed by saying, eg, "NULL expands to a null pointer
constant; the choice of which null pointer constant is implementation
defined." You haven't really given any kind of convincing reason,
merely stated that you believe that's the intent. In the absence of
any such reason, allowing NULL to define an implementation-defined
null pointer constant seems like a better fit to the existing
language, because otherwise that language would probably have been
rewritten to better express the intent you suggest.
It wouldn't make sense to use the phrase "implementa tion defined" only in a footnote.
I agree that it's better to put the "implementa tion defined" phrase
in the main text, in either interpretation; as mentioned above. 4. If we take 6.3.2.3 p3 as precisely delimiting the set of expressions that are null pointer constants, then, as you yourself pointed out, '((void*)0)' would not be a null pointer constant. Yet
int (*fp)(int); fp = ((void*)0);
works. (At least, I'm not aware of any implementation where it doesn't work.) This code isn't allowed to work (without a diagnostic) unless '((void*)0)' were a null pointer constant. So what are we to believe? That lots of implementations got it wrong, or that the set of expressions mentioned in 6.3.2.3 p3 is not exhaustive? The second alternative seems more likely. If the set of expressions mentioned in 6.3.2.3 p3 is not exhaustive, then of course any additional forms of null pointer constant would be implementation defined.
I believe the glitch in 6.3.2.3p3, which implies that (void*)0 is a null pointer constant but ((void*)0) isn't, is simply an oversight. I suspect the authors of the standard just assumed that an expression in parentheses is equivalent to the expression without parentheses -- and of course enclosing macro definitions in parentheses is almost always a good idea. Implementations actually conform to the intent of the standard in this case, rather than to the literal wording. I wouldn't infer anything significant from this (though I'd certainly like to see this corrected.)
A small correction - implementations conform to what *you presume* the
intent of the standard is. If implementation-defined null pointer
constants are allowed, then they may be conforming to the actual
standard and not just to the intent.
If your suspicion about simply forgetting about enclosing parentheses
were right, then other more complicated forms of "null pointer
constants" shouldn't work. Have you tried any of these? If not
you may be surprised by what you find. 5. In the absence of any clearly compelling argument to the contrary, the reading that puts less strain on the interpretation seems better. Basically, Occam's Razor. Unless there is specific evidence that an implementation is forbidden from defining particular forms of null pointer constants, it's a better match to the observed facts to assume that it's allowed.
I disagree. I find it much simpler to assume that the definition of "null pointer constant" means exactly what it says, modulo the parentheses glitch. The intent of the phrase "implementa tion-defined null pointer constant" in 7.17p3 is quite clear given this interpretation; there's no need to invent the idea of additional implementation-defined *forms* of null pointer constant. There's also no advantage in doing so; we have more than enough null pointer constants already without allowing implementations to invent their own.
If I may paraphrase, what you think is that the document authors
screwed up, because your interpretation is simpler? Or is it
the other way around?
Perhaps that was a little unfair. But I don't see any real substance
here; if one assumes your position, then everything is consistent and
clear. However that's equally true for the other position. I don't
see any reason, on those grounds, that anyone should prefer one
position over the other.
Tim Rentsch <tx*@alumnus.ca ltech.edu> writes: Keith Thompson <ks***@mib.or g> writes: Tim Rentsch <tx*@alumnus.ca ltech.edu> writes:
[...] > 5. In the absence of any clearly compelling argument to the contrary, > the reading that puts less strain on the interpretation seems better. > Basically, Occam's Razor. Unless there is specific evidence that an > implementation is forbidden from defining particular forms of null > pointer constants, it's a better match to the observed facts to > assume that it's allowed.
I disagree. I find it much simpler to assume that the definition of "null pointer constant" means exactly what it says, modulo the parentheses glitch. The intent of the phrase "implementa tion-defined null pointer constant" in 7.17p3 is quite clear given this interpretation; there's no need to invent the idea of additional implementation-defined *forms* of null pointer constant. There's also no advantage in doing so; we have more than enough null pointer constants already without allowing implementations to invent their own.
If I may paraphrase, what you think is that the document authors screwed up, because your interpretation is simpler? Or is it the other way around?
Perhaps that was a little unfair. But I don't see any real substance here; if one assumes your position, then everything is consistent and clear. However that's equally true for the other position. I don't see any reason, on those grounds, that anyone should prefer one position over the other.
There's not a whole lot more to be said, but I've just posted a
question to comp.std.c. Perhaps we can get an interpretation from the
folks who actually wrote the standard.
--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Keith Thompson <ks***@mib.or g> writes: Conceivably there might be some advantage (other than historical) in C's approach rather than defining single keyword for null pointers. I just can't think of anything. Can you?
I have my own opinions about what some of these are,
but perhaps we can get some other regulars to voice
their opinions on the subject. I don't want to get
involved in a debate about the relative merits of
the two approaches. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: Hiroki Horiuchi |
last post by:
Hello.
I wrote a program, but g++ warns
a.c:11: warning: invalid access to non-static data member `A::y' of NULL object
a.c:11: warning: (perhaps the `offsetof' macro was used incorrectly)
The program is like below.
class A
{
|
by: Exits Funnel |
last post by:
Consider this code which is a very trimmed down version of some I've
inherited and am trying to port from windows to g++:
//Begin test1.cpp
class foo { int i; int j; };
class bar
{
bar (int foo::* dataMember)
:offsetof (foo, *dataMember) //Call this Line (A)
|
by: Arthur J. O'Dwyer |
last post by:
As far as I know, C89/C90 did not contain the
now-standard offsetof() macro.
Did C89 mandate that structs had to have a consistent
layout? For example, consider the typical layout of
the following structure:
struct weird
{
int x; /* sizeof(int)==4 here */
|
by: luke |
last post by:
hi all,
i have another question.
I've read the FAQ regarding my former question (sizeof struct and
union) and in question 2.14 it talks about offset macro.
#define offsetof(type, mem) ((size_t) \
((char *)&((type *)0)->mem - (char *)(type *)0))
Can anyone explain me how it works.
1)I can't understand what "0" casted to (type *) means
|
by: Fred Zwarts |
last post by:
Consider the following definition:
typedef struct {
int a;
int b;
} s;
Now I have a function
void f (int i) { ... }
| |
by: Pawel |
last post by:
Hallo group members.
//p1.cpp
#include <stdio.h>
#include <linux/stddef.h>
struct Person {
int m_age;
char* m_name;
};
|
by: Kavya |
last post by:
offsetof(T,m) (size_t)&(((T*)0)->m)
Why do we always start from 0 in this macro to access the offset of
structure or union. Does standard guarantees that structure and union
reside at address 0? If yes, then what if I have two or more
structures. How can they reside at same address?.
|
by: Francine.Neary |
last post by:
Just out of personal curiosity :)
What do people use offsetof() for? I mean, I can understand why you'd
want to be able to take the address of a member of a struct, but you
can do that with just &(s.a) or similar. Why you'd care about the
offset (which surely depends on how the compiler chooses to lay the
struct out in memory), I don't really know. And if you did really
care, won't offset(s,a) just be &(s.a) - &s ?
|
by: mihirtr |
last post by:
Hi,
I have following structures and union
typedef struct
{
int a;
int b;
char *c;
}TEST_1;
|
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: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
|
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: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
|
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...
| |