当前位置:  开发笔记 > 编程语言 > 正文

#define是否在行业标准中被禁止?

如何解决《#define是否在行业标准中被禁止?》经验,为你挑选了10个好方法。

我是一年级计算机专业的学生,我的教授说#define的行业标准,以及被禁止#if,#ifdef,#else,和其他一些预处理指令.由于出乎意料的行为,他使用了"禁止"一词.

这准确吗?如果是这样的话?

事实上,是否存在禁止使用这些指令的任何标准?



1> Jonathan Lef..:

首先我听说过它.

没有; #define等等被广泛使用.有时使用过于广泛,但绝对使用.有些地方C标准要求使用宏 - 你无法轻易避免这些.例如,§7.5 错误说:

宏是

     EDOM
     EILSEQ
     ERANGE

它扩展为具有类型int,不同正值的整数常量表达式,并且适用于#if预处理指令; ...

鉴于此,很明显并非所有行业标准都禁止使用C预处理器宏指令.但是,各种组织都有"最佳实践"或"编码指南"标准,规定了对C预处理器使用的限制,尽管没有完全禁止使用它 - 它是C的固有部分,无法完全避免.通常,这些标准适用于在安全关键领域工作的人员.

您可以检查MISRA C(2012)标准的一个标准; 这往往会取代某些东西,但即便认识到#define有时需要等等(第8.20节,规则20.1至20.14涵盖了C预处理器).

美国宇航局GSFC(戈达德太空飞行中心)C编码标准简单地说:

只应在必要时使用宏.过度使用宏会使代码更难以读取和维护,因为代码不再读取或行为类似于标准C.

介绍性声明之后的讨论说明了函数宏的可接受用法.

该CERT C编码标准有很多关于使用预处理程序的指导方针,并暗示你应该尽量少用预处理程序,但并没有禁止其使用.

Stroustrup希望使预处理器在C++中无关紧要,但这还没有发生.正如彼得 指出的那样,一些C++标准,例如2005年左右的JSF AV C++编码标准(联合攻击战斗机,飞行器),决定了C预处理器的最小使用.从本质上讲,JSF AV C++规则将其限制为#include#ifndef XYZ_H/ #define XYZ_H/ .../#endifdance,以防止单个标头的多个包含.C++有一些在C中不可用的选项 - 特别是对类型常量的更好支持,然后可以在C不允许使用它们的地方使用它们.另见static constvs #definevsenum对那里问题的讨论.

最好尽量减少预处理器的使用 - 它经常被滥用至少与使用它一样多(参见Boost 预处理器 '库'来说明你可以用C预处理器走多远).

摘要

预处理器是C和的一个组成部分#define#if等不能完全避免.在这个问题的教授的说法是不普遍有效的:#define在行业标准一起被取缔#if,#ifdef,#else,和一些其它的宏是最好过的语句,但可能受到支持并明确提及具体的行业标准(但有关标准不包括ISO/IEC 9899:2011 - C标准.


需要注意的是大卫Hammen已提供的信息,约一个特定的C编码标准-在JPLÇ编码标准 -禁止很多事情,很多人用C使用,其中包括限制使用的C预处理(和限制使用的动态内存分配,并禁止递归 - 阅读它以查明原因,并确定这些原因是否与您相关).


读取C标准中的**7.5错误**.它*需要*使用宏.从字面上看.
一些MISRA规则要求/建议使用宏的某些限制,但它们相当普遍.实际上,我对他们的放纵感到惊讶.即使是`#define MAX(a,b)((a> b)?(a):( b))`也没关系,尽管它有潜在的危险.

2> Peter..:

不,禁止使用宏.

事实上,#include在头文件中使用保护是一种常见的技术,通常是强制性的,并且受到公认的编码指南的鼓励.有些人声称可以#pragma once替代它,但问题在于#pragma once- 根据定义,因为编译指示是编译器特定扩展的标准提供的钩子 - 是非标准的,即使它受到许多编译器的支持.

也就是说,#include由于宏引入的问题(不考虑范围等),有许多行业指南和鼓励的做法主动阻止除了守卫之外的所有宏的使用.在C++开发中,宏的使用比C开发更强烈.

不鼓励使用某些东西与禁止使用它是不同的,因为它仍然可以合法地使用它 - 例如,通过记录理由.



3> John Bode..:

某些编码标准可能会阻止甚至禁止使用#define创建带有参数的类似函数的宏,例如

#define SQR(x) ((x)*(x))

因为a)这样的宏不是类型安全的,而b)有人会不可避免地SQR(x++),这是不好的juju.

某些标准可能会阻止或禁止使用#ifdefs进行条件编译.例如,以下代码使用条件编译来正确打印size_t值.对于C99及更高版本,您使用%zu转换说明符; 对于C89及更早版本,您使用%lu并将值转换为unsigned long:

#if __STDC_VERSION__ >= 199901L
#  define SIZE_T_CAST
#  define SIZE_T_FMT "%zu"
#else
#  define SIZE_T_CAST (unsigned long)
#  define SIZE_T_FMT "%lu"
#endif
...
printf( "sizeof foo = " SIZE_T_FMT "\n", SIZE_T_CAST sizeof foo );

有些标准可能会强制要求您执行该模块两次,一次用于C89及更早版本,一次用于C99及更高版本:

/* C89 version */
printf( "sizeof foo = %lu\n", (unsigned long) sizeof foo );

/* C99 version */
printf( "sizeof foo = %zu\n", sizeof foo );

然后让Make(或Ant,或者你正在使用的任何构建工具)处理编译和链接正确的版本.对于这个荒谬过度的例子,但我已经看到代码是一个无法追踪的老鼠的#ifdefs 窝应该将条件代码分解成单独的文件.

但是,我不知道任何公司或行业组织已经完全禁止使用预处理器语句.



4> Andrew Henle..:

宏不能被"禁止".声明是无稽之谈.从字面上看.

例如,部分7.5错误的的C标准 需要使用宏:

1标题定义了几个宏,所有宏都与错误条件的报告有关.

2宏是

EDOM
EILSEQ
ERANGE

它扩展为具有类型int,不同正值的整数常量表达式,并且适用于#if预处理指令; 和

errno

它扩展为具有类型int和线程本地存储持续时间的可修改左值,其值由多个库函数设置为正误差数.如果为了访问实际对象而禁止宏定义,或者程序使用名称定义标识符errno,则行为是未定义的.

因此,不仅宏是C 的必需部分,在某些情况下不使用它们会导致未定义的行为.



5> Viktor Toth..:

不,#define不被禁止.#define然而,滥用可能不受欢迎.

例如,您可以使用

#define DEBUG

在您的代码中,以便稍后,您可以使用#ifdef DEBUG仅为调试目的指定代码的部分条件进行条件编译.我不认为任何心智正常的人会想要禁止这样的事情.使用的宏#define也在便携式程序中广泛使用,以启用/禁用特定于平台的代码的编译.

但是,如果你正在使用类似的东西

#define PI 3.141592653589793

你的老师可能理所当然地指出,PI用适当的类型声明为常数要好得多,例如,

const double PI = 3.141592653589793;

因为它允许编译器在PI使用时进行类型检查.

类似地(如上面的John Bode所述),类似函数的宏的使用可能会被拒绝,尤其是在可以使用模板的C++中.而不是

#define SQ(X) ((X)*(X))

考虑使用

double SQ(double X) { return X * X; }

或者,在C++中,更好的是,

template T SQ(T X) { return X * X; }

再一次,我们的想法是通过使用语言的设施而不是预处理器,允许编译器键入check并且(可能)生成更好的代码.

一旦您有足够的编码经验,您就会确切知道何时适合使用#define.在那之前,我认为你的老师强加某些规则和编码标准是一个好主意,但最好是他们自己应该知道并能够解释原因.全面禁止#define是荒谬的.



6> mikedu95..:

这是完全错误的,宏在C中被大量使用.初学者经常使用它们,但这并不是禁止它们进入行业的理由.一个经典的坏用法是#define succesor(n) n + 1.如果你期望2 * successor(9)得到20,那么你错了,因为那个表达式将被翻译为2 * 9 + 119而不是20.使用括号来获得预期的结果.


我不确定这个例子清楚地证明了初学者的错误用法,

7> luis.espinal..:

不,它没有被禁止.事实上,如果没有它,就不可能完成非平凡的多平台代码.


我100%同意你的看法.我只是补充说,在编写交叉编译器代码时,预处理器也很有用.
多平台和交叉编译器,我会说:)

8> Superlokkus..:

没有你的教授错了或你听错了什么.

#define是一个预处理器宏,条件编译和一些约定需要预处理器宏,这些约束不是简单地用C语言构建的.例如,在最近的C标准,即C99中,增加了对布尔的支持.但它不受语言支持"原生",而是由预处理器支持#define.请参阅stdbool.h的参考


@psraganvesh未定义的行为更多是由例如`*NULL`或`char foo [2]引起的; foo [2];`,所有编程错误.为了更好地了解未定义的行为,通常是UB的缩写,我推荐这个:http://c2.com/cgi/wiki?UndefinedBehavior
在我第二次询问他之后,他说过两次"因行为不明而在行业中被禁止",因为我还没有听说过其他任何地方
@psraganvesh*禁止*宏将导致每个C标准的未定义行为.请参阅我关于`errno`的答案 - 标准明确规定不使用`errno`宏会导致未定义的行为.

9> Daniel Farre..:

宏在GNU land C中使用相当多,并且没有条件预处理器命令就无法正确处理相同源文件的多个包含,因此这对我来说似乎是必不可少的语言特性.

也许你的课实际上是在C++上,尽管许多人都没有这样做,但是应该区别于C,因为它是一种不同的语言,我不能在那里代表宏.或许教授意味着他在班上禁止他们.无论如何,我确信SO社区会对他正在谈论的标准感兴趣,因为我非常确定所有C标准都支持使用宏.


大声笑我怎么能不知道我正在听哪一堂课,他在我第二次问他后两次专门说了两遍
C++中也需要宏.例如,没有其他方式(我知道)放入标题保护(`#ifndef HEADER_H #define HEADER_H ...#endif`)
@Quuxplusone #pragma几乎肯定不会因为成为一个pragma而成为C标准.Pragma保留用于实现定义的行为,因此将其添加到标准将破坏以不符合此新假设标准的方式使用它的每个编译器.因此,我认为最好尽可能避免这种情况,这对#ifndef来说非常有效
除了撰写提案的人之外,还有更多的东西进入标准.编译指示 - 在C和C++标准中 - 是为实现定义的行为提供一个钩子,实现可以自由地忽略`#pragma`的任何用法.因此,任何pragma都会被标准化,这简直就是幻想 - 这个概念与pragma是完全不一致的.一些供应商歪曲某些供应商特定功能作为标准的事实并没有这样做.

10> David Hammen..:

与迄今为止的所有答案相反,在高可靠性计算中经常禁止使用预处理器指令.这有两个例外,这些组织的使用是强制性的.这些是#include指令,以及在头文件中使用包含保护.这种禁令更可能在C++中而不是在C中.

这只是一个例子:16.1.1仅使用预处理器来实现包含保护,并包括包含保护的头文件.

另一个例子,这次是针对C而不是C++:C编程语言的JPL机构编码标准.这种C编码标准并没有完全禁止使用预处理器,但它接近了.具体来说,它说

规则20(预处理器使用)C预处理器的使用限于文件包含和简单宏.[十条规则8的权力].


我既不宽恕也不谴责这些标准.但是说它们不存在是荒谬的.


至少有一个禁止宏的环境与说它们在整个行业被禁止的情况完全不同.所以现有的答案既不错也不"荒谬".
@LightnessRacesinOrbit - 我没有说他们在整个行业都被禁止了.最受好评的(和IMNHO错误接受的)答案说"首先我听说过",以及其他一些类似的答案.我们这里有一位教授,他可能只知道一个行业,其中预处理器的使用受到严格限制,一个学生很可能错误地解释了教授所说的内容,以及一堆过度解释这个错误解释的问题的答案.这不仅仅是一个XY问题.这是一个XYZW问题.
推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有