LINUX.ORG.RU

Странное поведение gcc


0

0

Фрагмент кода 1:
n = 32;
printf( "n = %d\n", n );

m_mask = ( (uint32_t)1 << n ) - 1;// << ( 32 - n );
printf("mask = %x\n", m_mask);
Результат:
n = 32
mask = 0

Фрагмент кода 2:
n = 32;
// printf( "n = %d\n", n );

m_mask = ( (uint32_t)1 << n ) - 1;// << ( 32 - n );
printf("mask = %x\n", m_mask);
Результат:
mask = ffffffff

Собирается код g++ -O2. Есть идеи куда копать?

★★

Так в чем странное поведение? Конструкция сдвинет влево ( (uint32_t)1 << n ), а справа заполнит нулем.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

> Так в чем странное поведение? Конструкция сдвинет влево ( (uint32_t)1 << n ), а справа заполнит нулем.

А почему во втором случае (комментируем printf) получается другой результат?

Deleted
()
Ответ на: комментарий от Deleted

> А почему во втором случае (комментируем printf) получается другой результат?

Действительно. Что то странное. Попробовал у себя - комментирование первого принтфа на рез-т не влияет.
GCC-4.1.2.

andreyu ★★★★★
()

Какая версия GCC? У меня на GCC 3.4.6, 4.2.4, 4.3.3 и 4.4.0-alpha20090407 ошибка не проявилась. И приведи весь исходник и команду, которой компилируешь.

Deleted
()

x@x:~/1$ gcc -O2 test.c -o test
x@x:~/1$ ./test
n = 32
mask = ffffffff
mask = ffffffff
x@x:~/1$ gcc -O1 test.c -o test
x@x:~/1$ ./test
n = 32
mask = ffffffff
mask = ffffffff
x@x:~/1$ gcc -O0 test.c -o test
x@x:~/1$ ./test
n = 32
mask = 0
mask = 0
x@x:~/1$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3

LamerOk ★★★★★
()
Ответ на: комментарий от Delay

> Сделал все проще, m_mask = 0xFFFFFFFF << ( 32 - n ) но все равно gcc не прав:)

Может мне нужно отдохнуть, но исходя из исходной задачи, конструкция должна была быть такой:

unsigned int m_mask = ( (unsigned int)0xffffffff >> (32 - n) );

andreyu ★★★★★
()
Ответ на: комментарий от Deleted

> Какая версия GCC? У меня на GCC 3.4.6, 4.2.4, 4.3.3 и 4.4.0-alpha20090407 ошибка не проявилась. И приведи весь исходник и команду, которой компилируешь.

Пардон, это было 4.2 =). Хотя комментирование действительно не влияет. Зато влияет -O:

[2009.04.21 16:03:18] ivan@ivan-laptop ~/test
$ g++ test.cpp -o test && ./test 
n = 32
mask = 0

[2009.04.21 16:04:05] ivan@ivan-laptop ~/test
$ g++ -O2 test.cpp -o test && ./test 
n = 32
mask = ffffffff

Похоже надо в багзиллу писать...

Deleted
()
Ответ на: комментарий от Deleted

В тестовом файле у меня тоже ошибка не проявляется а вот оригинальной программе есть.
Полный исходник:

cidr.h
_______________________
#ifndef CIDR_H_
#define CIDR_H_

#include <string>

class Cidr
{
public:
	Cidr( uint32_t ip, uint32_t mask );
	Cidr( const std::string &addr );
	bool set( uint32_t ip, uint32_t mask = 0xFFFFFFFF );
	bool set( const std::string &addr );
	uint64_t get();
	std::string getS( int format );
	uint32_t getIp();
	std::string getIpS();
	uint32_t getMask();
	std::string getMaskS( int format = 0 );

	bool valid();

//	bool inNet( uint64_t cidr );
//	bool inNet( uint32_t ip, uint32_t mask = 0xFFFFFFFF );

private:
	uint32_t m_addr;
	uint32_t m_mask;
	uint32_t bitcount( uint32_t n );
};

#endif /* CIDR_H_ */


cidr.cpp
___________________

#include <sstream>

#include "cidr.h"

Cidr::Cidr( uint32_t ip, uint32_t mask )
{
	set( ip, mask );
}

Cidr::Cidr( const std::string &addr )
{
	set( addr );
}

bool Cidr::set( uint32_t ip, uint32_t mask )
{
	m_addr = ip;
	m_mask = mask;
	return valid();
}
bool Cidr::set( const std::string &addr )
{
	m_addr = 0;
	m_mask = 0;

	uint32_t a, b, c, d, a1, b1, c1, d1, n;
	if ( ( std::sscanf( addr.c_str(), "%3u.%3u.%3u.%3u/%3u.%3u.%3u.%3u", &a, &b, &c, &d, &a1, &b1, &c1, &d1) >= 8 )
		 && ( a <= 255 ) && ( b <= 255 ) && ( c <= 255) && ( d <= 255 )
		 && ( a1 <= 255 ) && ( b1 <= 255 ) && ( c1 <= 255) && ( d1 <= 255 ) )
	{
		m_addr = a;
		m_addr = m_addr << 8;
		m_addr |= b;
		m_addr = m_addr << 8;
		m_addr |= c;
		m_addr = m_addr << 8;
		m_addr |= d;
		m_mask = a1;
		m_mask = m_mask << 8;
		m_mask |= b1;
		m_mask = m_mask << 8;
		m_mask |= c1;
		m_mask = m_mask << 8;
		m_mask |= d1;
	}
	else if ( ( std::sscanf( addr.c_str(), "%3u.%3u.%3u.%3u/%2u", &a, &b, &c, &d, &n) >= 5 )
		 && ( a <= 255 ) && ( b <= 255 ) && ( c <= 255) && ( d <= 255 ) && ( n <= 32 ) )
	{
		m_addr = a;
		m_addr = m_addr << 8;
		m_addr |= b;
		m_addr = m_addr << 8;
		m_addr |= c;
		m_addr = m_addr << 8;
		m_addr |= d;

		n = 32;
//////// ВОЛШЕБНЫЙ printf ////////////
//		printf( "n = %d\n", n );

		m_mask = ( ( (uint32_t)1 << n ) - 1 ) << ( 32 - n );
		printf("mask = %x\n", m_mask);

//		m_mask = 0xFFFFFFFF << ( 32 - n );
	}
	return valid();
}

uint64_t Cidr::get()
{
	uint64_t res;
	res = m_addr;
	res = res << 32;
	res |= m_mask;
	return res;
}
std::string Cidr::getS( int format )
{
	std::string res;
	res = getIpS() + '/' + getMaskS( format );
	return res;
}
uint32_t Cidr::getIp()
{
	return m_addr;
}
std::string Cidr::getIpS()
{
	std::stringstream res;
	res
	<< (( m_addr & 0xFF000000 ) >> 24 ) << '.'
    << (( m_addr & 0x00FF0000 ) >> 16 ) << '.'
    << (( m_addr & 0x0000FF00 ) >> 8 ) << '.'
    <<  ( m_addr & 0x000000FF );
	return res.str();
}
uint32_t Cidr::getMask()
{
	return m_mask;
}
std::string Cidr::getMaskS( int format )
{
	std::stringstream res;

	switch ( format )
	{
	case 0:
		res
	    << (( m_mask & 0xFF000000 ) >> 24 ) << '.'
	    << (( m_mask & 0x00FF0000 ) >> 16 ) << '.'
	    << (( m_mask & 0x0000FF00 ) >> 8 ) << '.'
	    <<  ( m_mask & 0x000000FF );
		break;
	case 1:
	    res
	    << bitcount( m_mask );
		break;
	}
	return res.str();
}

bool Cidr::valid()
{
	return (( m_addr > 0 ) && ( m_mask > 0 ));
}

uint32_t Cidr::bitcount(uint32_t n)
 {
    /* works for 32-bit numbers only    */
    /* fix last line for 64-bit numbers */

    register uint32_t tmp;

    tmp = n - ((n >> 1) & 033333333333)
            - ((n >> 2) & 011111111111);
    return ((tmp + (tmp >> 3)) & 030707070707) % 63;
 }

main.cpp
_____________
#include "cidr.h"
#include <iostream>

int main(int argc, char* argv[]) {
	Cidr a( "192.168.1.2/24" );
//	std::cout << a.getIpS() << std::endl;
//	std::cout << a.getMaskS() << std::endl;

	return 0;
}

Delay ★★
() автор топика
Ответ на: комментарий от Delay

[light@light flow-tools]$ gcc --version
gcc (GCC) 4.3.2 20081105 (Red Hat 4.3.2-7)
Copyright (C) 2008 Free Software Foundation, Inc.
Это свободно распространяемое программное обеспечение. Условия копирования
приведены в исходных текстах. Без гарантии каких-либо качеств, включая
коммерческую ценность и применимость для каких-либо целей.

Delay ★★
() автор топика
Ответ на: комментарий от andreyu

> Может мне нужно отдохнуть, но исходя из исходной задачи, конструкция должна была быть такой:
>

> unsigned int m_mask = ( (unsigned int)0xffffffff >> (32 - n) );


Не, в оригинальной задаче нужно определенное количество старших бит установить в 1, просто на результат при n=32 не влияет вот я сдвиг в право и закомментил.

Delay ★★
() автор топика
Ответ на: комментарий от Delay

> А ты на какой версии gcc проверил?

3.4.6, 4.2.4, 4.3.3 и 4.4.0-alpha20090407

> И результат столь же неожиданный?:)


Да, без оптимизации - 0, с оптимизацией - ffffffff =).

Deleted
()

If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

В твоем случае результат непредставим => undefined behaviour => ты не можешь рассчитывать что он будет одинаков всегда.

dilmah ★★★★★
()
Ответ на: комментарий от Delay

С -O2 на g++ (Debian 4.3.2-1.1) 4.3.2, g++-4.1 (GCC) 4.1.3 20080704 (prerelease) (Debian 4.1.2-25)

Без printf:

//////// ВОЛШЕБНЫЙ printf ////////////
		//printf( "n = %d\n", n );

		m_mask = ( ( (uint32_t)1 << n ) - 1 ) << ( 32 - n );
		printf("mask = %x\n", m_mask);
  4016ad:	be ff ff ff ff       	mov    $0xffffffff,%esi
  4016b2:	89 03                	mov    %eax,(%rbx)
  4016b4:	31 c0                	xor    %eax,%eax
  4016b6:	e8 75 f9 ff ff       	callq  401030 <printf@plt>


С printf:

//////// ВОЛШЕБНЫЙ printf ////////////
		printf( "n = %d\n", n );
  4016ab:	89 03                	mov    %eax,(%rbx)
  4016ad:	31 c0                	xor    %eax,%eax
  4016af:	e8 7c f9 ff ff       	callq  401030 <printf@plt>

		m_mask = ( ( (uint32_t)1 << n ) - 1 ) << ( 32 - n );
		printf("mask = %x\n", m_mask);
  4016b4:	8b 44 24 34          	mov    0x34(%rsp),%eax
  4016b8:	be 01 00 00 00       	mov    $0x1,%esi
  4016bd:	bf 88 26 40 00       	mov    $0x402688,%edi
  4016c2:	89 c1                	mov    %eax,%ecx
  4016c4:	d3 e6                	shl    %cl,%esi
  4016c6:	b9 20 00 00 00       	mov    $0x20,%ecx
  4016cb:	29 c1                	sub    %eax,%ecx
  4016cd:	83 ee 01             	sub    $0x1,%esi
  4016d0:	31 c0                	xor    %eax,%eax
  4016d2:	d3 e6                	shl    %cl,%esi
  4016d4:	89 73 04             	mov    %esi,0x4(%rbx)
  4016d7:	e8 54 f9 ff ff       	callq  401030 <printf@plt>

summatus
()
Ответ на: комментарий от Delay

> Эээ, у меня вроде везде unsigned

значит, баг в компиляторе..

dilmah ★★★★★
()

без «волшебного printf» то же самое

$ gcc b.c
$ ./a.out
1 1
$ gcc -O2 b.c
$ ./a.out
0 0
$ gcc --version
gcc (Debian 4.3.3-3) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ cat b.c
#include <stdio.h>
#include <stdlib.h>

int main ()
{
        int n = 32;
        unsigned int m_mask1 = 1U << n;
        int m_mask2 = 1 << n;
        printf("%x %x\n", m_mask1, m_mask2);
        return 0;
}

вообще при переполнении << должен быть ноль или undefined behaviour ?
dilmah ?

Eshkin_kot ★★
()

Чего двоешники - уже написали багрепорт ? :) 

    m_mask = ((uint32_t)1 << n ) - 1;// << ( 32 - n );
 804839c:	8b 4d f8             	mov    -0x8(%ebp),%ecx
 804839f:	b8 01 00 00 00       	mov    $0x1,%eax
 80483a4:	d3 e0                	shl    %cl,%eax
 80483a6:	83 e8 01             	sub    $0x1,%eax
 80483a9:	89 45 f4             	mov    %eax,-0xc(%ebp)
    printf("mask = %x\n", m_mask); 
 80483ac:	8b 45 f4             	mov    -0xc(%ebp),%eax
 80483af:	89 44 24 04          	mov    %eax,0x4(%esp)
 80483b3:	c7 04 24 94 84 04 08 	movl   $0x8048494,(%esp)
 80483ba:	e8 f9 fe ff ff       	call   80482b8 <printf@plt>

В результате вы пытаетесь сдвинуть регистр на 32 позиции а для 386  допустимо только 0..31 процессор ничего не делает для значения 32, а для других он сделал бы CL mod 32 сдвигов. В итоге из 1 - 1 = 0. При оптимизации он видит константное значение и сразу вычисляет его как 0xffffffff на этапе компиляции.

monika
()
Ответ на: комментарий от Eshkin_kot

> В тестовом файле у меня тоже ошибка не проявляется а вот оригинальной программе есть.

Delay ★★
() автор топика
Ответ на: комментарий от monika

Еще раз, я уже писал, что разные значени при разной оптимизации понятны и объяснимы. А вот поведение при наличии/отсутствии printf нет. Попробуй собрать мой пример.

Delay ★★
() автор топика
Ответ на: комментарий от monika

> Чего двоешники - уже написали багрепорт ? :)

а при чем тут ассемблер? Стандарт Си специфицирует, что должен получиться ноль. Если не ноль -- багрепорт на gcc.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

>Стандарт Си специфицирует, что должен получиться ноль.

Можно ссылку на пункт в стандарте или цитату где по вашему мнению говорится что должен получиться ноль ?

monika
()
Ответ на: комментарий от monika

Моника, держи себя в руках:) Как тут может gdb помочь непонятно ... А что до пистона, то переписываю утилитку с перла, ибо на нем слишком медленно.

Delay ★★
() автор топика
Ответ на: комментарий от Delay

> Еще раз, я уже писал, что разные значени при разной оптимизации понятны и объяснимы. А вот поведение при наличии/отсутствии printf нет.

это можно объяснить, если результат << при переполнении является undefined behaviour, тогда его использование порождает вполне понятное неопределённое поведение :)

Eshkin_kot ★★
()
Ответ на: комментарий от Deleted

Напиши - только не обижайся если тебя помидорами закидают :) Чтобы получилось как вы хотите нужно перед битовыми сдвигами проверять находится cl в заданном диапазоне, тогда лучше на пистоне или жабе пишите, там все надежно тормозит.

monika
()

Delay,

  6.5.7 Bitwise shift operators
  Syntax
1         shift-expression:
                  additive-expression
                  shift-expression << additive-expression
                  shift-expression >> additive-expression
  Constraints
2 Each of the operands shall have integer type.
  Semantics
3 The integer promotions are performed on each of the operands. The type of the result is
  that of the promoted left operand. If the value of the right operand is negative or is
  greater than or equal to the width of the promoted left operand, the *behavior is undefined*.


так что это не ошибка.

Eshkin_kot ★★
()
Ответ на: комментарий от monika

> Можно ссылку на пункт в стандарте или цитату где по вашему мнению говорится что должен получиться ноль ?

Ноль не обязвтелен:)

5.8 - Shift operators
...
The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
...

Delay ★★
() автор топика
Ответ на: комментарий от Eshkin_kot

Спасибо, я уже сам стандарт почитал:)

Delay ★★
() автор топика
Ответ на: комментарий от Eshkin_kot

К счастью люди разрабатывающие стандарты маразмом не страдают :)

monika
()

И мне доводилось с этим стлкнуться, когда отлаживал программу для микроконтроллеров ATMega8 и ATMega16 архитектуры AVR. Использовал компилятор avr-gcc. Оказалось, что компилятор не умеет правильно сдвигать слово более чем на 16 бит.

sw1972
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.