私はsiを知らない

この記事の目的は、全員、特にCプログラマーに「私はCを知らない」と言うようにすることです。

Cの暗いコーナーは見た目よりもずっと近く、些細なコード行でも未定義の動作をしていることを示したいと思います。



この記事は一連の質問として構成されています。 回答は白で書かれています。 すべての例は、個別のソースコードファイルです。



1。

int i;
int i = 10;

      
      







Q: ? ( , , ? , , compound statement)



A: , . (tentative definition), , ( ).



2.

extern void bar(void);

void foo(int *x)
{
  int y = *x;  /* (1) */
  if(!x)       /* (2) */
  {
    return;    /* (3) */
  }

  bar();
  return;
}

      
      







Q: , bar() , x — ( ). ?



A: , . x — , (1) undefined behavior, : (1), return (2) (1). , , . (1) , x (2) (3) (dead code elimination). y *x volatile, .



.




3.

:

#define ZP_COUNT 10

void func_original(int *xp, int *yp, int *zp)
{
  int i;
  for(i = 0; i < ZP_COUNT; i++)
  {
    *zp++ = *xp + *yp;
  }
}

      
      







:

void func_optimized(int *xp, int *yp, int *zp)
{
  int tmp = *xp + *yp;
  int i;
  for(i = 0; i < ZP_COUNT; i++)
  {
    *zp++ = tmp;
  }
}

      
      







Q: , zp?



A: , yp == zp.



4.

double f(double x)
{
  assert(x != 0.);
  return 1. / x;
}

      
      







Q: inf ()? , IEEE 754 ( ). assert (NDEBUG ).



A: . x, , 1e-309.



5.

int my_strlen(const char *x)
{
  int res = 0;
  while(*x)
  {
    res++;
    x++;
  }
  return res;
}

      
      







Q: null-terminated . .



A: int : , int . size_t.



6.

#include <stdio.h>
#include <string.h>

int main()
{
  const char *str = "hello";
  size_t length = strlen(str);
  size_t i;
  for(i = length - 1; i >= 0; i--)
  {
    putchar(str[i]);
  }
  putchar('\n');
  return 0;
}

      
      







Q: . ?



A: size_t — . i , i >= 0 .



7.

#include <stdio.h>

void f(int *i, long *l)
{
  printf("1. v=%ld\n", *l); /* (1) */
  *i = 11;                  /* (2) */
  printf("2. v=%ld\n", *l); /* (3) */
}

int main()
{
  long a = 10;
  f((int *) &a, &a);
  printf("3. v=%ld\n", a);
  return 0;
}

      
      







little-endian . :

1. v=10    2. v=11    3. v=11
1. v=10    2. v=10    3. v=11

      
      







Q: ?



A: undefined behavior, , (strict aliasing). (2) int, long . ( , .) (3) long, (1).



8.

#include <stdio.h>

int main()
{
  int array[] = { 0, 1, 2 };
  printf("%d %d %d\n", 10, (5, array[1, 2]), 10);
}

      
      







Q: ? undefined behavior, ?



A: , . , . : 10 2 10.



, (, f(a(), b())) : a(), b() .




9.

unsigned int add(unsigned int a, unsigned int b)
{
  return a + b;
}

      
      







Q: add(UINT_MAX, 1)?



A: , 2^(CHAR_BIT * sizeof(unsigned int)). 0.



10.

int add(int a, int b)
{
  return a + b;
}

      
      







Q: add(INT_MAX, 1)?



A: — undefined behavior.



11.

int neg(int a)
{
  return -a;
}

      
      







Q: undefined behavior? , ?



A: neg(INT_MIN). (. twos complement, ), INT_MIN , INT_MAX. -INT_MIN — undefined behavior.



12.

int div(int a, int b)
{
  assert(b != 0);
  return a / b;
}

      
      







Q: undefined behavior? , ?



A: , div(INT_MIN, -1) — . .



— Dmitri Gribenko <gribozavr@gmail.com>



Creative Commons License

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.



All Articles