简体   繁体   English

ANSI C之前的结构选择器使用

[英]Pre-ANSI C use of struct selectors

A few years ago, before standardization of C, it was allowed to use struct selectors on addresses. 几年前,在标准化C之前,允许在地址上使用结构选择器。 For example, the following code was allowed and frequently used. 例如,以下代码被允许并经常使用。

#define PTR 0xAA000
struct {  int integ; };

func() {
   int i;
   i = PTR->integ;    /* here, c is set to the first int at PTR */
   return c;
}

Maybe it wasn't very neat, but I like it. 也许不是很好,但是我喜欢。 In my opinion, the power and the versatility of this language relies also on its lack of constraints. 我认为,这种语言的功能和多功能性还取决于其缺乏约束。 Nowadays, compilers just dump an error. 如今,编译器只是转储一个错误。 I'd like to know if it is possible to remove this restraint in the GNU C compiler. 我想知道是否有可能在GNU C编译器中消除这种限制。

PS: similar code was used on the UNIX kernel by the inventors of C. (in V6, some dummy structures have been declared in param.h) PS:C的发明者在UNIX内核上使用了类似的代码(在V6中,在param.h中声明了一些虚拟结构)

'A few years ago' is actually a very, very long time ago. “几年前”实际上是非常非常长的时间。 AFAICR, the C in 7th Edition UNIX™ (1979, a decade before the C89 standard was defined) didn't support that notation any more (but see below). AFAICR(第七版UNIX™中的C)(1979年,比C89标准定义早了十年)不再支持该表示法(但请参见下文)。

The code shown in the question only worked when all structure members of all structures shared the same name space. 问题中显示的代码仅在所有结构的所有结构成员共享相同的名称空间时才有效。 That meant that structure.integ or pointer->integ always referred to an int at the start of a structure because there was only one possible structure member integ across the entire program. 这意味着由于在整个程序中只有一个可能的结构成员integ ,所以structure.integpointer->integ在结构开始时总是引用int

Note that in 'modern' C (1978 onwards), you cannot reference the structure type; 请注意,在“现代” C(从1978年开始)中,您不能引用结构类型。 there's neither a structure tag nor a typedef for it — the type is useless. 它既没有结构标签,也没有typedef-类型是无用的。 The original code also references an undefined variable c . 原始代码还引用了未定义的变量c

To make it work, you'd need something like: 要使其工作,您需要类似以下内容:

#define PTR 0xAA000
struct integ {  int integ; };

int func(void)
{
   struct integ *ptr = (struct integ *)PTR;
   return ptr->integ;
}

C for 7th Edition UNIX 第七版C的UNIX

I suggested that the C with 7th Edition UNIX supported separate namespaces for separate structure types. 我建议带有第7版UNIX的C为单独的结构类型支持单独的命名空间。 However, the C Reference Manual published with the UNIX Programmer's Manual Vol 2 mentions in §8.5 Structures: 但是,与UNIX程序员手册第2卷一起发布的C参考手册在§8.5结构中提到:

The names of structure members and structure tags may be the same as ordinary variables, since a distinction can be made by context. 结构成员和结构标签的名称可以与普通变量相同,因为可以根据上下文进行区分。 However, names of tags and members must be distinct. 但是,标记和成员的名称必须不同。 The same member name can appear in different structures only if the two members are of the same type and if their origin with respect to their structure is the same; 仅当两个成员具有相同的类型并且它们的起源在结构上相同时,相同的成员名称才能出现在不同的结构中。 thus separate structures can share a common initial segment. 因此,单独的结构可以共享一个公共的初始段。

However, that same manual also mentions the notations (see also What does =+ mean in C ): 但是,该手册也提到了这些符号(另请参见=+在C中的含义 ):

§7.14.2 lvalue =+ expression §7.14.2左值= +表达式
§7.14.3 lvalue =- expression §7.14.3左值=-表达式
§7.14.4 lvalue =* expression §7.14.4左值= *表达式
§7.14.5 lvalue =/ expression §7.14.5左值= /表达式
§7.14.6 lvalue =% expression §7.14.6左值=%表达式
§7.14.7 lvalue =>> expression §7.14.7lvalue = >>表达式
§7.14.8 lvalue =<< expression §7.14.8lvalue = <<表达式
§7.14.9 lvalue =& expression §7.14.9左值=&表达式
§7.14.10 lvalue =^ expression §7.14.10左值= ^表达式
§7.14.11 lvalue = | §7.14.11左值= | expression 表达

The behavior of an expression of the form ''E1 =op E2'' may be inferred by taking it as equivalent to ''E1 = E1 op E2''; 形式为“ E1 = op E2”的表达式的行为可以通过将其等同于“ E1 = E1 op E2”来推断。 however, E1 is evaluated only once. 但是,E1仅被评估一次。 Moreover, expressions like ''i =+ p'' in which a pointer is added to an integer, are forbidden. 此外,禁止将指针添加到整数之类的表达式“ i = + p”。

AFAICR, that was not supported in the first C compilers I used (1983 — I'm ancient, but not quite that ancient); AFAICR,在我使用的第一个C编译器中不支持(1983年-我很古老,但还不那么古老); only the modern += notations were allowed. 仅允许使用现代+=表示法。 In other words, I don't think the C described by that reference manual was fully current when the product was released. 换句话说,我认为该参考手册中描述的C在产品发布时并不是最新的。 (I've not checked my 1st Edition of K&R — does anyone have one on hand to check?) You can find the UNIX 7th Edition manuals online at http://cm.bell-labs.com/7thEdMan/ . (我没有检查过我的K&R的第1版-是否有人在手检查?)您可以从http://cm.bell-labs.com/7thEdMan/在线找到UNIX 7版手册。

By giving the structure a type name and adjusting your macro slightly you can achieve the same effect in your code: 通过为结构指定类型名称并略微调整宏,可以在代码中实现相同的效果:

typedef struct { int integ; } PTR_t;
#define PTR ((PTR_t*)0xAA000)

I'd like to know if it is possible to remove this restraint in the GNU C compiler. 我想知道是否有可能在GNU C编译器中消除这种限制。

I'm reasonably sure the answer is no -- that is, unless you rewrite gcc to support the older version of the language. 我有理由确定答案是否定的-除非您重写gcc以支持该语言的较早版本。

The gcc manual documents the -traditional command-line option: gcc手册记录了-traditional命令行选项:

'-traditional' '-traditional-cpp' '-传统''-传统-cpp'

Formerly, these options caused GCC to attempt to emulate a pre-standard C compiler. 以前,这些选项导致GCC尝试模拟标准C编译器。 They are now only supported with the `-E' switch. 现在仅支持使用-E开关。 The preprocessor continues to support a pre-standard mode. 预处理器继续支持预标准模式。 See the GNU CPP manual for details. 有关详细信息,请参见GNU CPP手册。

This implies that modern gcc (the quote is from the 4.8.0 manual) no longer supports pre-ANSI C. 这意味着现代gcc(引自4.8.0手册)不再支持ANSI C之前的版本。

The particular feature you're referring to isn't just pre-ANSI, it's very pre-ANSI. 您所指的特定功能不仅是pre-ANSI, 还很是 pre-ANSI。 The ANSI standard was published in 1989. The first edition of K&R was published in 1978, and as I recall the language it described didn't support the feature you're looking for. ANSI标准于1989年发布。K&R的第一版于1978年发布,并且我记得它所描述的语言不支持您要查找的功能。 The initial release of gcc was in 1987, so it's very likely that no version of gcc has ever supported that feature. gcc的最初版本是1987年,因此很可能没有 gcc版本支持该功能。

Furthermore, enabling such a feature would break existing code which may depend on the ability to use the same member name in different structures. 此外,启用此功能将破坏现有代码,这可能取决于在不同结构中使用相同成员名称的能力。 (Traces of the old rules survive in the standard C library, where for example the members of type struct tm all have names starting with tm_ ; in modern C that would not be necessary.) (在C语言标准库中保留了旧规则的内容,例如struct tm类型的成员都以tm_开头的名称;而在现代C语言中则不必要。)

You might be able to find sources for an ancient C compiler that works the way you want. 您也许能够找到按照您想要的方式运行的古老C编译器的源代码。 The late Dennis Ritchie's home page would be a good starting point for that. 已故的丹尼斯·里奇(Dennis Ritchie)的主页将是一个很好的起点。 It's not at all obvious that you'd be able to get such a compiler working on any modern system without a great deal of work. 显然,您无需进行大量工作就可以使这样的编译器在任何现代系统上运行。 And the result would be a compiler that doesn't support a number of newer features of C that you might find useful, such as the long , signed , and unsigned keywords, the ability to pass structures by value, function prototypes, and diagnostics for attempts to mix pointers and integers. 结果将是编译器不支持您可能会发现有用的C的许多较新功能,例如longsignedunsigned关键字,按值传递结构的功能,函数原型以及用于诊断的功能。尝试混合使用指针和整数。

C is better now than it was then. 现在的C比以前更好 There are a few dangerous things that are slightly more difficult than they were, but I'm not aware that any actual expressive power has been lost. 有一些危险的事情比以前要困难一些,但是我不知道任何实际的表达能力已经丧失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM