Tag: c89

通过严格解释C标准允许对可能无效的指针进行操作

原始问题 (请参阅“编辑:更新的方案”) 这个问题可能是一个或另一个方面的重复,涉及到超出范围的对象的指针的未定义行为的大量问题。但我在这里找到的所有问题主要是专门的用例。 所以我想把这个问题颠倒过来,不要问是否禁止某些事情,但是究竟允许什么? 有一个可能的场景:你有一个带有指针的函数 – 你不知道它是否来自一个(仍然)有效的对象。 在所有情况下哪些操作不是未定义的行为? 哪个可能有未指定的副作用? int * myFunc(const int * const A, int * B) { … } 编辑:更新的方案 在对问题的评论和Matt McNabbs的回答中 ,有人指出UB最有可能上升,因为在调用场景中的函数期间使用了无效指针(s值)。 因此,我会稍微改变一下场景(按照Keith Thompsons回答的例子): int *ptr = malloc(sizeof *ptr); /* the value of ptr is now valid, possibly NULL */ if (ptr != NULL) { /* the value of ptr is […]

NULL指针作为数组末尾的标记

我阅读了Kernigan&Ritchie撰写的第二版“C编程语言”第6.3段。 一些结构: struct key { char *word; int count; } keytab[NKEYS] { { “auto”, 0 }, { “break”, 0 }, { “case”, 0 }, { “char”, 0 }, { “const”, 0 }, { “continue”, 0 } }; 作者写了这篇文章: 数量NKEYS是keytab中的关键字数量。 虽然我们可以手工计算,但是通过机器来完成它会更加容易和安全,特别是如果列表可能会发生变化。 一种可能性是使用空指针终止初始化程序列表,然后沿keytab循环直到找到结尾。 如果枚举只包含指针,那么一切都会很清楚: struct key { char *word; char *description; } keytab[NKEYS] { { “auto”, “” […]

MS VS 2008和C99

我感兴趣地读了一篇文章“支持C99的普遍性如何?”。 其中一条评论指出微软不支持C99。 但注释符号//适用于VS 2008,此符号位于C99中。 我有两个问题: VS 2008在多大程度上支持C99? 在同一代码中将C89和C99语法混合在一起是否可以? 因此,如果我在C89中编写代码然后发表评论//。 这意味着我有混合编码。 那么在这种情况下编译器会做什么呢? 首先用c89检查我的代码,然后用C99检查我是否使用//进行评论?

在C89中使用可变参数函数而不传递参数或最终参数?

假设我有一个可变函数foo(int tmp, …) ,当调用foo函数时我需要知道有多少个参数。 我知道有两种方法可以找出有多少参数: 在调用foo时使用最后一个参数,比如-1,所以你的函数调用将是这样的: foo(tmp, 1, 2, 9, -1) ,当你在foo内部并且va_arg调用返回-1时你知道你已阅读所有函数参数 在foo中再添加一个参数,程序员将拥有参数总数,因此你可以像这样调用foo: foo(tmp, 5, 1, 2, 3, 4, 5) foo(tmp, 2, 7, 8) foo(tmp, 5, 1, 2, 3, 4, 5)或foo(tmp, 2, 7, 8) 我曾经遵循第一种方式,曾经有过以下错误。 随着代码: expr_of_type(expr, boolexpr_e, newtable_e, nil_e, -1) 其中expr_of_type是一个可变参数函数,并检查expr(第一个参数)是否是以下类型之一(boolexpr_e或new_table_e或nil_e具有所有类型的枚举类型)。 我一个人意外地写道: expr_of_type(expr, boolexpr_e, newtable_e, nil_e -1) 我忘记了nil_e和-1之间的逗号,因为nil_e有一个枚举类型,nil_e – 1是一个有效的表达式,因为nil_e不是0,当尝试获取expr_of_type参数时,给定的可变参数函数没有找到-1作为最后一个参数继续搜索创建一个花了我一些时间才发现的bug。 我也没有找到第二种方式,因为当从可变参数函数中添加或删除一个参数时,您需要更改包含总参数数量的参数。 在寻找更好的使用/创建可变参数函数的方法时,我发现了可变元宏 ,它可以解决我在使用第一种方式时遇到的错误。 但是可变参数宏可用于C99标准。 […]

C90中的可变长度结构

GNU C中允许零长度数组,因此可以进行初始化 struct line { int length; char contents[0]; }; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); thisline->length = this_length; 注意:我在这里指的是这个页面: http : //gcc.gnu.org/onlinedocs/gcc/Zero-Length.html (提供C中可变长度结构的基本介绍) 它继续说:“在ISO C90中,你必须给内容一个长度为1,这意味着你要浪费空间或使参数复杂化到malloc。” 那是什么意思? 有人可以举例说明如何在C90中初始化变长结构以帮助理解吗?

`long`保证与`size_t`一样宽

当寻找unsigned long证据足以容纳size_t以便成为printf参数时,我遇到了两个事实(oid)s。 首先,这个答案表明long确实不足以保证size_t足够大。 另一方面,我看到这个答案建议在前C99中使用printf(“%lu”, (unsigned long)x) , x是size_t 。 所以问题是你可以假设或者你保证在C99之前持有size_t long足够long 。 另一个问题是,是否有任何保证size_t适合任何其他标准化整数类型(除了明显的例外,如ssize_t , ptrdiff_t等)。

ANSI C编译器可以删除延迟循环吗?

考虑ANSI C中的while循环,其唯一目的是延迟执行: unsigned long counter = DELAY_COUNT; while(counter–); 我已经看到这很多用于强制执行嵌入式系统的延迟,例如。 没有sleepfunction,定时器或中断是有限的。 我对ANSI C标准的解读是,这可以通过符合标准的编译器完全删除。 它没有5.1.2.3中描述的副作用: 访问易失性对象,修改对象,修改文件或调用执行任何这些操作的函数都是副作用,这些都是执行环境状态的变化。 ……并且本节还说: 实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用)。 这是否意味着可以优化循环? 即使counter是volatile ? 笔记: 这与编译器允许消除无限循环不完全相同? ,因为它指的是无限循环,并且出现关于何时允许程序终止的问题。 在这种情况下,程序肯定会在某个时刻通过这条线,优化与否。 我知道GCC会做什么(删除-O1或更高的循环,除非counter是volatile ),但我想知道标准规定了什么。

在隐式函数声明的情况下的默认参数提升

我试图搜索旧问题,但我没有解决我的问题。 我试着解释我的怀疑; 假设在c89模式下工作,如果在函数调用之前没有函数的原型,则存在函数的隐式声明,函数的类型为int ,参数通过Default Argument Promotions转换: char或short int类型的对象(无论是否有符号)被提升为int或unsigned int,视情况而定; 并且float类型的对象被提升为double类型。 所以,如果我写这样的代码,我同意它必须工作: int main(void){ char a; short b,c; f(a,b,c); return 0; } int f(int a,int b,int c){ return 1; } 和这里一样: int main(void){ float a; short b,c; f(a,b,c); return 0; } int f(double a,int b,int c){ return 1; } 但我不明白为什么以下2个案例有效 /*a)*/ int main(void){ short a,b; float […]

返回C中布尔表达式的值

由于不值得一提的原因,我想知道布尔表达式是否有标准的定义值。 例如 int foo () { return (bar > 5); } 上下文是我担心我们的团队将TRUE定义为不同于1的东西,我担心有人会这样做: if (foo() == TRUE) { /* do stuff */ } 我知道最好的选择就是做 if (foo()) 但你永远不知道。 布尔表达式是否有定义的标准值,还是由编译器决定? 如果有的话,标准值是否包含在C99中? 怎么样C89?

安全浮点分部

我的代码中有一些地方,我想确保2个任意浮点数(32位单精度)的除法不会溢出。 目标/编译器不保证(明确地)对-INF / INF的良好处理和(不完全保证IEEE 754的exception值 – (可能未定义) – 并且目标可能会改变)。 此外,我无法对这几个特殊地点的输入进行保存,我必须使用C90标准库。 我已经读过每个计算机科学家应该知道的关于浮点算术的内容但是说实话,我有点迷失了。 所以……我想问一下社区,如果以下代码可以解决问题,并且有更好/更快/更高/更正/更正的方法: #define SIGN_F(val) ((val >= 0.0f)? 1.0f : -1.0f) float32_t safedivf(float32_t num, float32_t denum) { const float32_t abs_denum = fabs(denum); if((abs_denum < 1.0f) && ((abs_denum * FLT_MAX) <= (float32_t)fabs(num)) return SIGN_F(denum) * SIGN_F(num) * FLT_MAX; else return num / denum; } 编辑:根据Pascal Cuoq的建议,将((abs_denum * […]