你遇到的C的常见的未定义/未指定的行为是什么? [英] What are the common undefined/unspecified behavior for C that you run into?

查看:478
本文介绍了你遇到的C的常见的未定义/未指定的行为是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C语言中未指定的行为的一个例子是对函数的参数求值的顺序。它可能是向左或从右到左,你只是不知道。这将影响如何 foo(c ++,c) foo(++ c,c)

解决方案

还有什么未指定的行为会让意想不到的程序员感到惊讶? >一个语言律师的问题。 Hmkay。



我的个人top3:


  1. 违反严格别名规则

  2. 违反严格别名规则

  3. 违反严格别名规则



    < )


编辑这是一个错误两次的示例:



(假设为32位整数和小尾数)

  float funky_float_abs )
{
unsigned int temp = *(unsigned int *)& a;
temp& = 0x7fffffff;
return *(float *)& temp;
}

该代码试图通过bit-twiddling获取浮点数的绝对值



但是,通过从一个类型转换到另一个类型来创建指向某个对象的指针的结果是无效的。C.编译器可以假定不同类型的指针不指向同一块内存。这适用于所有类型的指针,除了void *和char *(符号无关紧要)。



在上面的例子中,我做了两次。一次获得浮点a的int别名,并且一次将值转换回float。



有三种有效的方法可以做同样的操作。



在演员表演时使用char或void指针。这些总是别名,所以它们是安全的。

  float funky_float_abs(float a)
{
float temp_float = a;
// valid,因为它是一个char指针。这些都是特别的。
unsigned char * temp =(unsigned char *)& temp_float;
temp [3]& = 0x7f;
return temp_float;
}

使用memcopy。 Memcpy接受无效指针,因此它也将强制别名。

  float funky_float_abs(float a)
{
int i;
float result;
memcpy(& i,& a,sizeof(int));
i& = 0x7fffffff;
memcpy(& result,& i,sizeof(int));
return result;
}

第三种有效方式:使用联合。这是明确的未定义自C99:

  float funky_float_abs(float a)
{
union
{
unsigned int i;
float f;
} cast_helper;

cast_helper.f = a;
cast_helper.i& =; 0x7fffffff;
return cast_helper.f;
}


An example of unspecified behavior in the C language is the order of evaluation of arguments to a function. It might be left to right or right to left, you just don't know. This would affect how foo(c++, c) or foo(++c, c) gets evaluated.

What other unspecified behavior is there that can surprise the unaware programmer?

解决方案

A language lawyer question. Hmkay.

My personal top3:

  1. violating the strict aliasing rule
  2. violating the strict aliasing rule
  3. violating the strict aliasing rule

    :-)

Edit Here is a little example that does it wrong twice:

(assume 32 bit ints and little endian)

float funky_float_abs (float a)
{
  unsigned int temp = *(unsigned int *)&a;
  temp &= 0x7fffffff;
  return *(float *)&temp;
}

That code tries to get the absolute value of a float by bit-twiddling with the sign bit directly in the representation of a float.

However, the result of creating a pointer to an object by casting from one type to another is not valid C. The compiler may assume that pointers to different types don't point to the same chunk of memory. This is true for all kind of pointers except void* and char* (sign-ness does not matter).

In the case above I do that twice. Once to get an int-alias for the float a, and once to convert the value back to float.

There are three valid ways to do the same.

Use a char or void pointer during the cast. These always alias to anything, so they are safe.

float funky_float_abs (float a)
{
  float temp_float = a;
  // valid, because it's a char pointer. These are special.
  unsigned char * temp = (unsigned char *)&temp_float;
  temp[3] &= 0x7f;
  return temp_float;
}

Use memcopy. Memcpy takes void pointers, so it will force aliasing as well.

float funky_float_abs (float a)
{
  int i;
  float result;
  memcpy (&i, &a, sizeof (int));
  i &= 0x7fffffff;
  memcpy (&result, &i, sizeof (int));
  return result;
}

The third valid way: use unions. This is explicitly not undefined since C99:

float funky_float_abs (float a)
{
  union 
  {
     unsigned int i;
     float f;
  } cast_helper;

  cast_helper.f = a;
  cast_helper.i &= 0x7fffffff;
  return cast_helper.f;
}

这篇关于你遇到的C的常见的未定义/未指定的行为是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆