A conversão implícita do Objective-C perde a precisão do número inteiro 'NSUInteger' (também conhecido como 'não assinado longo') para o aviso 'int'

187

Estou trabalhando em alguns exercícios e recebi um aviso informando:

A conversão implícita perde a precisão do número inteiro: 'NSUInteger' (também conhecido como 'não assinado longo') para 'int'

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool {

        NSArray *myColors;

        int i;
        int count;

        myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];

        count = myColors.count; //  <<< issue warning here

        for (i = 0; i < count; i++)

        NSLog (@"Element %i = %@", i, [myColors objectAtIndex: i]);
    }

    return 0;
}

Captura de tela

monkeyboy
fonte

Respostas:

470

O countmétodo de NSArrayretorna NSUIntegere na plataforma OS X de 64 bits

  • NSUIntegeré definido como unsigned longe
  • unsigned long é um número inteiro não assinado de 64 bits.
  • int é um número inteiro de 32 bits.

Portanto, inté um tipo de dados "menor" que NSUInteger, portanto, o aviso do compilador.

Consulte também NSUInteger na "Referência de tipos de dados de fundação":

Ao criar aplicativos de 32 bits, o NSUInteger é um número inteiro não assinado de 32 bits. Um aplicativo de 64 bits trata o NSUInteger como um número inteiro não assinado de 64 bits.

Para corrigir esse aviso do compilador, você pode declarar a countvariável local como

NSUInteger count;

ou (se tiver certeza de que sua matriz nunca conterá mais do que 2^31-1elementos!), adicione uma conversão explícita:

int count = (int)[myColors count];
Martin R
fonte
19
Só para adicionar - votei nesta resposta, pois recebi uma carga de avisos e erros de repente no meu projeto do Xcode 5. Você mencionou 64 bits, o que me levou a examinar minhas configurações de compilação. O Xcode mudou para o modo de 64 bits, o que gerou erros. Mudar de volta para arvm7 corrigiu todos eles.
Robert J. Clegg
1
@ Tander, existe uma diferença de desempenho entre a compilação de 64 bits e o armv7?
Shaun Budhram 13/03/14
1
@ ShaunBudhram Pelo jeito, não. Eu não vi nenhuma diferença. Só fará diferença nos aplicativos que usam a CPU pesadamente - os jogos, por exemplo, veriam um benefício compilando por 64 bits.
Robert J. Clegg
7
"A partir de 1º de fevereiro de 2015, os novos aplicativos iOS carregados na App Store devem incluir suporte a 64 bits ..." - Notícias e atualizações de desenvolvedores da Apple, 20 de outubro de 2014
Pang
2
@JayprakashDubey: A Apple não vê os avisos do seu compilador porque você envia o aplicativo compilado binário à App Store. Portanto, seu aplicativo não pode ser rejeitado devido a avisos do compilador. Claro que você deve corrigi-los para que seu aplicativo funcione corretamente.
Martin R
24

Ao contrário da resposta de Martin, transmitir para int (ou ignorar o aviso) nem sempre é seguro, mesmo que você saiba que sua matriz não possui mais de 2 ^ 31-1 elementos. Não ao compilar para 64 bits.

Por exemplo:

NSArray *array = @[@"a", @"b", @"c"];

int i = (int) [array indexOfObject:@"d"];
// indexOfObject returned NSNotFound, which is NSIntegerMax, which is LONG_MAX in 64 bit.
// We cast this to int and got -1.
// But -1 != NSNotFound. Trouble ahead!

if (i == NSNotFound) {
    // thought we'd get here, but we don't
    NSLog(@"it's not here");
}
else {
    // this is what actually happens
    NSLog(@"it's here: %d", i);

    // **** crash horribly ****
    NSLog(@"the object is %@", array[i]);
}
Adrian
fonte
6
Você está certo em que lançar o resultado indexOfObject:seria uma má idéia. Minha resposta foi direcionada para o código específico da pergunta e o countmétodo não pode retornar NSNotFound. Não recomendei transmitir para int ou ignorar avisos em geral. Desculpe se isso não estava claro. Na verdade, seu código de exemplo geraria um aviso if (i == NSNotFound)se compilado para 64 bits, para que o problema não passasse despercebido.
Martin R
@ Adrian: Se você não se importa, o que você sugere que o solicitante faça?
moonman239
@ moonman239 Em geral, eu usaria uma variável do tipo correto, se possível (a primeira sugestão de @ MartinR) em vez de lançar (a segunda). Como ele aponta, o elenco é seguro nesse caso em particular, mas acho que é um péssimo hábito entrar, pois pode ter consequências inesperadas (como no meu exemplo). Postei porque fui mordido por essa situação específica (embora esse seja um bom argumento sobre o aviso do compilador ==, que devo ter perdido).
Adrian
2
Eu acho que count será usado com muito mais frequência do que indexOfObject, e inchar um loop for com NSInteger apenas para não ter um estilo de codificação "ruim" é um absurdo. Você deve prestar atenção exclusivamente para indexOfObject e certifique-se de usar NSIntegers lá, tudo o que simplesmente conta algo é bom, int, especialmente dentro de métodos concentrar
NikkyD
5

Alterar chave em Projeto> Configuração da compilação " verifique as chamadas para printf / scanf : NO "

Explicação: [Como funciona]

Verifique as chamadas para printf e scanf, etc., para garantir que os argumentos fornecidos tenham tipos apropriados para a sequência de formato especificada e se as conversões especificadas na sequência de formato fazem sentido.

Espero que funcione

Outro aviso

a conversão implícita do objetivo c perde a precisão inteira 'NSUInteger' (também conhecida como 'não assinado longo') para 'int

Altere a chave " conversão implícita para 32Bits Type> Debug> * 64 architecture: No "

[ cuidado: pode anular outro aviso de conversão da arquitetura de 64 bits] .

Darshit Shah
fonte
se você quiser converter sua biblioteca de 32 bits em 64 bits, essa é uma opção promissora.
San
2

Fazer a conversão de expicit para o "int" resolve o problema no meu caso. Eu tive o mesmo problema. Assim:

int count = (int)[myColors count];
Vladimir Despotovic
fonte
ou é chamado "implícito"? LOL :) Nos dois casos, funcionou.
Vladimir Despotovic