2015-10-20 3 views
1

Когда я пытаюсь запустить этот код как есть, я получаю сообщение компилятора «error: несовместимые типы в обратном порядке». Я отметил местоположение ошибки в моем коде. Если я выйду из строки, то компилятор будет счастлив.несовместимый тип возврата из функции struct - C

Проблема заключается в том, что я хочу вернуть значение, представляющее недопустимый ввод функции (который в этом случае вызывает f2 (2).) Я хочу, чтобы структура возвращалась с данными, если функция вызывается без использования 2 в качестве параметр.

Я чувствую только два пути, чтобы либо:

  1. сделать функция возвращает указатель STRUCT вместо мертвой на структура, но тогда моя функция звонящий будет выглядеть смешно, как я должен изменить yb до y-> b, и операция может быть медленнее из-за дополнительного шага выборки данных в памяти.

  2. Выделить дополнительную память, нулевой байт заполнить ее и установить возвращаемое значение для структуры в этом месте в памяти. (пример: return x[nnn]; вместо return x[0];). Этот подход будет использовать больше памяти, а некоторая обработка с нулевым байтом заполняет его.

В конечном счете, я ищу решение, которое будет самым быстрым и чистым (с точки зрения кода) в долгосрочной перспективе. Если мне нужно зацикнуться на использовании -> для обращения к элементам элементов, то я думаю, что это путь.

У кого-нибудь есть решение, использующее наименьшую мощность процессора?

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

    typedef struct{ 
    long a; 
    char b; 
    }ab; 

    static char dat[500]; 

    ab f2(int set){ 
     ab* x=(ab*)dat; 
     if (set==2){return NULL;} 
     if (set==1){ 
     x->a=1; 
     x->b='1'; 
     x++; 
     x->a=2; 
     x->b='2'; 
     x=(ab*)dat; 
     } 
     return x[0]; 
    } 

    int main(){ 
     ab y; 
     y=f2(1); 
     printf("%c",y.b); 
     y.b='D'; 
     y=f2(0); 
     printf("%c",y.b); 
     return 0; 
    } 

ответ

4

Если вам нужна скорость, это конкретная реализация.

Обратите внимание, что Linux x86-64 ABI определяет, что struct из два (точно) скалярные членов (то есть, целые числа, в два раза, или указатели, -Какой все уместить в одной машине, но не зарегистри- struct и т.д. .. которые являются совокупными данными) возвращается через два регистра (без прохождения через стек), и это довольно быстро.

BTW

 if (set==2){return NULL;} //wrong 

, очевидно, неправильно. Вы могли бы написать:

if (set==2) return (aa){0,0}; 

Кроме того,

ab* x=(ab*)dat; // suspicious 

выглядит подозрительным ко мне (так как вы return x[0]; позже). Вам не гарантируется, что dat соответствующим образом выровнен (например, до 8 или 16 байт), а на некоторых платформах (особенно x86-64), если dat несовместим, вы по крайней мере теряете производительность (на самом деле это undefined behavior).

Кстати, я хотел бы предложить, чтобы всегда возвращаться с инструкциями, как return (aa){l,c}; (где l является выражением конвертируемого в long и c является выражением конвертируемого в char); это, вероятно, проще всего читать и будет оптимизировано для загрузки двух возвращаемых регистров.

Конечно, если вы заботитесь о производительности, для целей бенчмаркинга вы должны включить оптимизацию (и предупреждения), например. скомпилировать с gcc -Wall -Wextra -O2 -march=native при использовании GCC; на моей системе (Linux/x86-64 с GCC 5.2) малая функция

ab give_both(long x, char y) 
    { return (ab){x,y}; } 

компилируется (с gcc -O2 -march=native -fverbose-asm -S) в:

  .globl give_both 
     .type give_both, @function 
give_both: 
.LFB0: 
     .file 1 "ab.c" 
     .loc 1 7 0 
     .cfi_startproc 
.LVL0: 
     .loc 1 7 0 
     xorl %edx, %edx  # D.2139 
     movq %rdi, %rax  # x, x 
     movb %sil, %dl  # y, D.2139 
     ret 
     .cfi_endproc 

вы видите, что весь код использует регистры, и нет память используется на всех ..

+0

Что такое скалярный член? Из физики я знаю, что скаляр - это значение, которое имеет только величину, но не направление. Что скаляр в программировании? –

+0

Подробности приведены в ABI. Но 'int',' double' и 'char *' - все скалярные типы –

1

Я хотел бы использовать возвращаемое значение как код ошибки, и вызывающий абонент передает указатель на его struct, такие как:

int f2(int set, ab *outAb); // returns -1 if invalid input and 0 otherwise 
+0

Это работает, но на x86-64 это, вероятно, менее эффективно. См. Мой ответ, почему ... –